I'm developing a .NET MAUI frontend and an ASP.NET Core Web API backend with SignalR for real-time order notifications. Everything works perfectly when running locally, but after deploying the API to Azure App Service, the SignalR connection from the MAUI app fails.
I've already configured web sockets and ARR affinity to "On" in the Azure App Service settings and set up CORS in my Program.cs to allow AllowAnyHeader(), AllowAnyMethod() and AllowCredentials().
Here is the frontend code:
hubConnection = new HubConnectionBuilder()
.WithUrl($"{TokenEndpoints.RegisterAlertEndPoint}?userId={userId}&companyKy={CompanyKey}", options => {
options.SkipNegotiation = true;
options.Transports = HttpTransportType.WebSockets;
})
.ConfigureLogging(logging =>
{
logging.AddDebug();
logging.SetMinimumLevel(LogLevel.Debug); // Log everything
})
.Build();
// Start the SignalR connection
// await hubConnection.StartAsync();
Task.Run(async () =>
{
await InvokeAsync(async () =>
{
await hubConnection.StartAsync();
});
});
// Handle incoming notifications
hubConnection.On<string>("ReceiveMessage", (message) =>
{
// Add notification to the list and refresh UI
//notifications.Add(message);
NotificationMessage = message;
Console.WriteLine($"Notification received: {message}");
MainThread.BeginInvokeOnMainThread(() =>
{
// Show the notification dialog
ShowNotificationDialog();
});
});
This is the backend Web API code:
public class OrderHub : Hub
{
private static Dictionary<string, Dictionary<string, List<string>>> companyUserConnections = new Dictionary<string, Dictionary<string, List<string>>>();
private readonly ConnectionMappingService _connectionMappingService;
private readonly ILogger<OrderHub> _logger;
public OrderHub(ConnectionMappingService connectionMappingService, ILogger<OrderHub> logger)
{
_connectionMappingService = connectionMappingService;
_logger = logger;
}
// When a client connects to the hub
public override async Task OnConnectedAsync()
{
// Get the userId and companyKey from the query string
var userId = Context.GetHttpContext().Request.Query["userId"].ToString();
var companyKey = Context.GetHttpContext().Request.Query["companyKy"].ToString();
var userName = Context.GetHttpContext().Request.Query["userName"].ToString();
if (!string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(companyKey))
{
// Add the connection to the dictionary
if (!companyUserConnections.ContainsKey(companyKey))
{
companyUserConnections[companyKey] = new Dictionary<string, List<string>>();
}
if (!companyUserConnections[companyKey].ContainsKey(userId))
{
companyUserConnections[companyKey][userId] = new List<string>();
}
companyUserConnections[companyKey][userId].Add(Context.ConnectionId);
_connectionMappingService.Add(companyKey, userId, Context.ConnectionId);
_logger.LogInformation($"New connection: {Context.ConnectionId}");
await Clients.Caller.SendAsync("ReceiveMessage", $"Welcome, user {userName} !");
}
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
// Get the userId and companyKey from the query string
var userId = Context.GetHttpContext().Request.Query["userId"].ToString();
var companyKey = Context.GetHttpContext().Request.Query["companyKy"].ToString();
if (!string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(companyKey) && companyUserConnections.ContainsKey(companyKey))
{
if (companyUserConnections[companyKey].ContainsKey(userId))
{
companyUserConnections[companyKey][userId].Remove(Context.ConnectionId);
if (!companyUserConnections[companyKey][userId].Any())
{
companyUserConnections[companyKey].Remove(userId);
}
if (!companyUserConnections[companyKey].Any())
{
companyUserConnections.Remove(companyKey);
}
_connectionMappingService.Remove(companyKey, userId);
}
}
_logger.LogInformation($"connection Disconnected: {Context.ConnectionId}");
await base.OnDisconnectedAsync(exception);
}
}
I tested
await _hubContext.Clients.All.SendAsync("ReceiveMessage", "New Order Testing");
this to send messages to the frontend. When I try it locally, it works. But after publishing it to Azure, it's not working.
Is the Azure Free Tier (for App Service) likely the root cause of this connection failure?
Please help me solve this issue.
Microsoft.AspNetCore.SignalR.Client's HubConnectionBuilder to connect and log events. Doesawait connection.StartAsync()succeed or throw, and what's the full exception? Handle and log theClosedand reconnection events. What happens?Publish to Azure App Servicedoc pages mentions limit per tier. If you follow the link to the Azure App Service limits table you'll see Free Tier allows 5 concurrent websocket connections. A unit test won't hit that limit, but running multiple MAUI apps at the same time will.