![]() |
VOOZH | about |
dotnet add package I-Synergy.Framework.AspNetCore.Monitoring --version 2026.10618.11733
NuGet\Install-Package I-Synergy.Framework.AspNetCore.Monitoring -Version 2026.10618.11733
<PackageReference Include="I-Synergy.Framework.AspNetCore.Monitoring" Version="2026.10618.11733" />
<PackageVersion Include="I-Synergy.Framework.AspNetCore.Monitoring" Version="2026.10618.11733" />Directory.Packages.props
<PackageReference Include="I-Synergy.Framework.AspNetCore.Monitoring" />Project file
paket add I-Synergy.Framework.AspNetCore.Monitoring --version 2026.10618.11733
#r "nuget: I-Synergy.Framework.AspNetCore.Monitoring, 2026.10618.11733"
#:package I-Synergy.Framework.AspNetCore.Monitoring@2026.10618.11733
#addin nuget:?package=I-Synergy.Framework.AspNetCore.Monitoring&version=2026.10618.11733Install as a Cake Addin
#tool nuget:?package=I-Synergy.Framework.AspNetCore.Monitoring&version=2026.10618.11733Install as a Cake Tool
Real-time monitoring and communication infrastructure using SignalR for ASP.NET Core applications. This package provides SignalR hub integration, monitor services for publishing events, connection management, and group-based messaging for building real-time dashboards, notifications, and collaboration features.
Install the package via NuGet:
dotnet add package I-Synergy.Framework.AspNetCore.Monitoring
In your Program.cs:
using ISynergy.Framework.AspNetCore.Monitoring.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add monitoring with SignalR (specify your entity type)
builder.Services.AddMonitorSignalR<MonitorEvent>();
builder.Services.AddControllers();
var app = builder.Build();
// Map the monitor hub
app.MapHub<MonitorHub>("/hubs/monitor");
app.Run();
Publish events to connected clients:
using ISynergy.Framework.Monitoring.Abstractions.Services;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IMonitorService<OrderEvent> _monitorService;
public OrdersController(IMonitorService<OrderEvent> monitorService)
{
_monitorService = monitorService;
}
[HttpPost]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderRequest request)
{
var order = await CreateOrderAsync(request);
// Publish event to all users in the account group
await _monitorService.PublishAsync(
channel: request.AccountId.ToString(),
eventname: "OrderCreated",
data: new OrderEvent
{
OrderId = order.Id,
Status = "Created",
CreatedAt = DateTime.UtcNow
});
return Ok(order);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateOrderStatus(
int id,
[FromBody] UpdateOrderStatusRequest request)
{
var order = await UpdateOrderAsync(id, request);
// Notify users about status change
await _monitorService.PublishAsync(
channel: order.AccountId.ToString(),
eventname: "OrderStatusChanged",
data: new OrderEvent
{
OrderId = order.Id,
Status = order.Status,
UpdatedAt = DateTime.UtcNow
});
return Ok(order);
}
}
public class OrderEvent
{
public int OrderId { get; set; }
public string Status { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
}
Connect to the SignalR hub from your frontend:
import * as signalR from "@microsoft/signalr";
// Configure connection with authentication
const connection = new signalR.HubConnectionBuilder()
.withUrl("/hubs/monitor", {
accessTokenFactory: () => getAuthToken()
})
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Information)
.build();
// Listen for order events
connection.on("OrderCreated", (event) => {
console.log("New order created:", event);
updateOrdersList(event);
});
connection.on("OrderStatusChanged", (event) => {
console.log("Order status changed:", event);
updateOrderStatus(event);
});
// Listen for user connection events
connection.on("Connected", (message) => {
console.log(`User connected: ${message.Data}`);
updateOnlineUsers(message);
});
connection.on("Disconnected", (message) => {
console.log(`User disconnected: ${message.Data}`);
updateOnlineUsers(message);
});
// Start connection
async function startConnection() {
try {
await connection.start();
console.log("SignalR Connected");
} catch (err) {
console.error("SignalR Connection Error:", err);
setTimeout(startConnection, 5000);
}
}
// Handle disconnections
connection.onclose(async () => {
await startConnection();
});
// Get authentication token
function getAuthToken() {
return localStorage.getItem("authToken");
}
// Start the connection
startConnection();
Connect from a .NET application:
using Microsoft.AspNetCore.SignalR.Client;
public class MonitorClient : IAsyncDisposable
{
private readonly HubConnection _connection;
public MonitorClient(string hubUrl, string accessToken)
{
_connection = new HubConnectionBuilder()
.WithUrl(hubUrl, options =>
{
options.AccessTokenProvider = () => Task.FromResult(accessToken);
})
.WithAutomaticReconnect()
.Build();
// Register event handlers
_connection.On<OrderEvent>("OrderCreated", OnOrderCreated);
_connection.On<OrderEvent>("OrderStatusChanged", OnOrderStatusChanged);
_connection.On<HubMessage<string>>("Connected", OnUserConnected);
_connection.On<HubMessage<string>>("Disconnected", OnUserDisconnected);
}
public async Task StartAsync()
{
await _connection.StartAsync();
}
private void OnOrderCreated(OrderEvent orderEvent)
{
Console.WriteLine($"Order created: {orderEvent.OrderId}");
}
private void OnOrderStatusChanged(OrderEvent orderEvent)
{
Console.WriteLine($"Order {orderEvent.OrderId} status: {orderEvent.Status}");
}
private void OnUserConnected(HubMessage<string> message)
{
Console.WriteLine($"User connected: {message.Data}");
}
private void OnUserDisconnected(HubMessage<string> message)
{
Console.WriteLine($"User disconnected: {message.Data}");
}
public async ValueTask DisposeAsync()
{
if (_connection != null)
{
await _connection.DisposeAsync();
}
}
}
// Usage
var client = new MonitorClient("https://api.example.com/hubs/monitor", authToken);
await client.StartAsync();
ISynergy.Framework.AspNetCore.Monitoring.Hubs/
└── MonitorHub # SignalR hub with authentication
ISynergy.Framework.AspNetCore.Monitoring.Services/
└── MonitorService<TEntity> # Publish events to hub groups
ISynergy.Framework.AspNetCore.Monitoring.Extensions/
├── ServiceCollectionExtensions # DI configuration
├── HostApplicationBuilderExtensions # Builder configuration
└── ApplicationBuilderExtensions # Middleware configuration
The MonitorHub automatically creates groups based on user ID and account ID:
using ISynergy.Framework.Monitoring.Abstractions.Services;
public class NotificationService
{
private readonly IMonitorService<NotificationEvent> _monitorService;
public NotificationService(IMonitorService<NotificationEvent> monitorService)
{
_monitorService = monitorService;
}
public async Task SendToUserAsync(string userId, NotificationEvent notification)
{
// Send to specific user's group
await _monitorService.PublishAsync(
channel: userId,
eventname: "Notification",
data: notification);
}
public async Task SendToAccountAsync(Guid accountId, NotificationEvent notification)
{
// Send to all users in an account
await _monitorService.PublishAsync(
channel: accountId.ToString(),
eventname: "Notification",
data: notification);
}
public async Task BroadcastAsync(NotificationEvent notification)
{
// Send to all connected users
await _monitorService.PublishAsync(
channel: "all",
eventname: "Notification",
data: notification);
}
}
Define strongly-typed events for different scenarios:
// Base event
public abstract class MonitorEvent
{
public string EventId { get; set; } = Guid.NewGuid().ToString();
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
}
// Specific event types
public class OrderEvent : MonitorEvent
{
public int OrderId { get; set; }
public string Status { get; set; }
public decimal Amount { get; set; }
}
public class InventoryEvent : MonitorEvent
{
public int ProductId { get; set; }
public int Quantity { get; set; }
public string Action { get; set; } // Added, Removed, Updated
}
public class UserActivityEvent : MonitorEvent
{
public string UserId { get; set; }
public string Action { get; set; }
public string Resource { get; set; }
}
// Register multiple monitor services
builder.Services.AddMonitorSignalR<OrderEvent>();
builder.Services.AddSingleton<IMonitorService<InventoryEvent>, MonitorService<InventoryEvent>>();
builder.Services.AddSingleton<IMonitorService<UserActivityEvent>, MonitorService<UserActivityEvent>>();
Track connection states in your hub:
using ISynergy.Framework.AspNetCore.Monitoring.Hubs;
using Microsoft.AspNetCore.SignalR;
public class CustomMonitorHub : MonitorHub
{
private readonly IConnectionTracker _connectionTracker;
public CustomMonitorHub(
ILogger<CustomMonitorHub> logger,
IConnectionTracker connectionTracker)
: base(logger)
{
_connectionTracker = connectionTracker;
}
public override async Task OnConnectedAsync()
{
await base.OnConnectedAsync();
var accountId = Context.User.GetAccountId();
var userId = Context.User.GetUserId();
// Track connection
await _connectionTracker.AddConnectionAsync(
Context.ConnectionId,
userId,
accountId);
// Send current online users to the connected client
var onlineUsers = await _connectionTracker.GetOnlineUsersAsync(accountId);
await Clients.Caller.SendAsync("OnlineUsers", onlineUsers);
}
public override async Task OnDisconnectedAsync(Exception exception)
{
var accountId = Context.User.GetAccountId();
var userId = Context.User.GetUserId();
// Remove connection
await _connectionTracker.RemoveConnectionAsync(
Context.ConnectionId,
userId,
accountId);
await base.OnDisconnectedAsync(exception);
}
}
Build a real-time monitoring dashboard:
// Backend service
public class DashboardService
{
private readonly IMonitorService<DashboardMetric> _monitorService;
private readonly IMetricsCollector _metricsCollector;
private Timer _timer;
public DashboardService(
IMonitorService<DashboardMetric> monitorService,
IMetricsCollector metricsCollector)
{
_monitorService = monitorService;
_metricsCollector = metricsCollector;
}
public void StartMonitoring(Guid accountId)
{
_timer = new Timer(async _ =>
{
var metrics = await _metricsCollector.GetCurrentMetricsAsync();
await _monitorService.PublishAsync(
channel: accountId.ToString(),
eventname: "DashboardUpdate",
data: new DashboardMetric
{
ActiveUsers = metrics.ActiveUsers,
OrdersPerHour = metrics.OrdersPerHour,
Revenue = metrics.Revenue,
ServerLoad = metrics.ServerLoad
});
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
}
public class DashboardMetric
{
public int ActiveUsers { get; set; }
public int OrdersPerHour { get; set; }
public decimal Revenue { get; set; }
public double ServerLoad { get; set; }
}
Frontend (React example):
import { useEffect, useState } from 'react';
import * as signalR from '@microsoft/signalr';
interface DashboardMetric {
activeUsers: number;
ordersPerHour: number;
revenue: number;
serverLoad: number;
}
export function Dashboard() {
const [metrics, setMetrics] = useState<DashboardMetric | null>(null);
const [connection, setConnection] = useState<signalR.HubConnection | null>(null);
useEffect(() => {
const newConnection = new signalR.HubConnectionBuilder()
.withUrl('/hubs/monitor', {
accessTokenFactory: () => getAuthToken()
})
.withAutomaticReconnect()
.build();
newConnection.on('DashboardUpdate', (metric: DashboardMetric) => {
setMetrics(metric);
});
newConnection.start()
.then(() => console.log('Connected to monitoring hub'))
.catch(err => console.error('Connection error:', err));
setConnection(newConnection);
return () => {
newConnection.stop();
};
}, []);
return (
<div className="dashboard">
<MetricCard
title="Active Users"
value={metrics?.activeUsers ?? 0}
/>
<MetricCard
title="Orders/Hour"
value={metrics?.ordersPerHour ?? 0}
/>
<MetricCard
title="Revenue"
value={`$${metrics?.revenue?.toFixed(2) ?? '0.00'}`}
/>
<MetricCard
title="Server Load"
value={`${metrics?.serverLoad?.toFixed(1) ?? '0.0'}%`}
/>
</div>
);
}
Implement collaborative editing features:
public class DocumentService
{
private readonly IMonitorService<DocumentChangeEvent> _monitorService;
public DocumentService(IMonitorService<DocumentChangeEvent> monitorService)
{
_monitorService = monitorService;
}
public async Task UpdateDocumentAsync(
Guid documentId,
string userId,
DocumentChange change)
{
// Save the change
await SaveChangeAsync(documentId, change);
// Notify all users viewing this document
await _monitorService.PublishAsync(
channel: documentId.ToString(),
eventname: "DocumentChanged",
data: new DocumentChangeEvent
{
DocumentId = documentId,
UserId = userId,
Change = change,
Timestamp = DateTime.UtcNow
});
}
}
// Client-side (TypeScript)
connection.on("DocumentChanged", (event) => {
if (event.userId !== currentUserId) {
// Apply changes from other users
applyDocumentChange(event.change);
}
});
Send instant notifications to users:
public class NotificationHub
{
private readonly IMonitorService<Notification> _monitorService;
public NotificationHub(IMonitorService<Notification> monitorService)
{
_monitorService = monitorService;
}
public async Task SendNotificationAsync(
string userId,
string title,
string message,
NotificationType type)
{
await _monitorService.PublishAsync(
channel: userId,
eventname: "Notification",
data: new Notification
{
Title = title,
Message = message,
Type = type,
Timestamp = DateTime.UtcNow
});
}
}
// Client-side
connection.on("Notification", (notification) => {
showToast(notification.title, notification.message, notification.type);
});
Use groups to efficiently broadcast messages to multiple connected clients without iterating through all connections.
Always implement automatic reconnection on the client side to handle network interruptions gracefully.
Monitor SignalR connection count and message throughput to ensure your infrastructure can handle the load.
Example unit tests for monitoring services:
using ISynergy.Framework.Monitoring.Abstractions.Services;
using Microsoft.AspNetCore.SignalR;
using Moq;
using Xunit;
public class MonitorServiceTests
{
[Fact]
public async Task PublishAsync_PublishesToCorrectGroup()
{
// Arrange
var mockHubContext = new Mock<IHubContext<MonitorHub>>();
var mockClients = new Mock<IHubClients>();
var mockGroupClients = new Mock<IClientProxy>();
mockHubContext.Setup(h => h.Clients).Returns(mockClients.Object);
mockClients.Setup(c => c.Group(It.IsAny<string>())).Returns(mockGroupClients.Object);
var service = new MonitorService<OrderEvent>(mockHubContext.Object);
var orderEvent = new OrderEvent
{
OrderId = 123,
Status = "Created"
};
// Act
await service.PublishAsync("account-123", "OrderCreated", orderEvent);
// Assert
mockClients.Verify(c => c.Group("account-123"), Times.Once);
mockGroupClients.Verify(
c => c.SendCoreAsync(
"OrderCreated",
It.Is<object[]>(o => o[0] == orderEvent),
default),
Times.Once);
}
}
For more information about the I-Synergy Framework:
For issues, questions, or contributions, please visit the GitHub repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.10618.11733 | 0 | 6/18/2026 |
| 2026.10618.11702-preview | 0 | 6/18/2026 |
| 2026.10616.12121 | 95 | 6/16/2026 |
| 2026.10616.11904-preview | 73 | 6/16/2026 |
| 2026.10616.10010 | 88 | 6/15/2026 |
| 2026.10615.12240-preview | 88 | 6/15/2026 |
| 2026.10615.10047-preview | 88 | 6/14/2026 |
| 2026.10614.10112-preview | 90 | 6/13/2026 |
| 2026.10612.12341-preview | 94 | 6/12/2026 |
| 2026.10612.12110-preview | 81 | 6/12/2026 |
| 2026.10612.11941-preview | 94 | 6/12/2026 |
| 2026.10610.10831 | 96 | 6/10/2026 |
| 2026.10610.10706-preview-pr... | 83 | 6/10/2026 |
| 2026.10609.11323-preview | 80 | 6/9/2026 |
| 2026.10607.11905-preview | 94 | 6/7/2026 |
| 2026.10607.11454-preview | 80 | 6/7/2026 |
| 2026.10606.11854-preview | 91 | 6/6/2026 |
| 2026.10603.11238-preview | 88 | 6/3/2026 |
| 2026.10602.12203-preview | 94 | 6/2/2026 |
| 2026.10602.11949-preview | 90 | 6/2/2026 |