C# Blazor+;SQLTableDependency+;信号器:从OnChange事件通知特定组
我有一个Blazor应用程序,它使用SQLTableDependency检测数据库更改,然后通过SignalR通知所有客户机更改。这是可行的,但我需要一种能够检测更改并只通知特定信号器组的方法。因为SQLTableDependency不关心是谁在数据库中插入、更改或删除了记录,所以我也不确定如何知道要发送更新的组。请参阅下面关于我的应用程序和我正在努力实现的更多详细信息 我们为每个客户建立了一个新的组织。一个组织有自己的资产列表,并且可以有多个用户 Organization.csC# Blazor+;SQLTableDependency+;信号器:从OnChange事件通知特定组,c#,.net-core,signalr,blazor,signalr-hub,C#,.net Core,Signalr,Blazor,Signalr Hub,我有一个Blazor应用程序,它使用SQLTableDependency检测数据库更改,然后通过SignalR通知所有客户机更改。这是可行的,但我需要一种能够检测更改并只通知特定信号器组的方法。因为SQLTableDependency不关心是谁在数据库中插入、更改或删除了记录,所以我也不确定如何知道要发送更新的组。请参阅下面关于我的应用程序和我正在努力实现的更多详细信息 我们为每个客户建立了一个新的组织。一个组织有自己的资产列表,并且可以有多个用户 Organization.cs pub
public class Organization
{
public int OrganizationId { get; set; }
public string OrganizationName { get; set; }
public List<Asset> Assets { get; set; }
public List<ApplicationUser> Users { get; set; }
public bool IsDisabled { get; set; }
}
public class Asset
{
public int AssetId { get; set; }
public string SerialNumber { get; set; }
public int OrganizationId { get; set; }
public virtual Organization Organization { get; set; }
public DateTime DateAdded { get; set; }
}
ApplicationUser.cs
public class ApplicationUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int OrganizationId { get; set; }
public virtual Organization Organization { get; set; }
public List<Connection> Connections { get; set; }
public string Timezone { get; set; }
}
AssetService.cs
public class AssetService : IAssetService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public AssetService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public async Task<Asset> AddAssetAsync(Asset asset, string currentUserName)
{
try
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetService<DataContext>();
if (asset.Device != null)
{
db.Entry(asset.Device).State = EntityState.Modified;
}
asset.DateAdded = DateTime.UtcNow;
await db.Assets.AddAsync(asset);
await db.SaveChangesAsync();
return asset;
}
}
catch (System.Exception ex)
{
throw ex;
}
}
}
公共类资产服务:IAssetService
{
专用readonly IServiceScopeFactory\u serviceScopeFactory;
公共资产服务(IServiceScopeFactory服务ScopeFactory)
{
_serviceScopeFactory=serviceScopeFactory;
}
公共异步任务AddAssetAsync(资产,字符串currentUserName)
{
尝试
{
使用(var scope=\u serviceScopeFactory.CreateScope())
{
var db=scope.ServiceProvider.GetService();
如果(asset.Device!=null)
{
db.Entry(asset.Device).State=EntityState.Modified;
}
asset.DateAdded=DateTime.UtcNow;
wait db.Assets.AddAsync(资产);
等待db.saveChangesSync();
归还资产;
}
}
catch(System.Exception-ex)
{
掷骰子;
}
}
}
AssetHub.cs-信号机集线器
public class ChatHub : Hub
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IServiceScopeFactory _serviceScopeFactory;
public ChatHub(UserManager<ApplicationUser> userManager, IServiceScopeFactory serviceScopeFactory)
{
_userManager = userManager;
_serviceScopeFactory = serviceScopeFactory;
}
public async Task SendAssetToGroup(string userName, string location, Asset asset)
{
if (!string.IsNullOrWhiteSpace(userName))
{
var user = await _userManager.Users.Include(x => x.Connections).SingleAsync(x => x.UserName == userName);
if (user != null)
{
var group = $"{user.AccountId}-{location}";
await Clients.Group(group).SendAsync("AssetUpdate", user.Email, asset);
}
}
}
public override async Task OnConnectedAsync()
{
var httpContext = Context.GetHttpContext();
var location = httpContext.Request.Query["location"];
using (var scope = _serviceScopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetService<ApplicationDbContext>();
if (!string.IsNullOrWhiteSpace(userName))
{
var user = await db.Users.Include(x => x.Connections).SingleAsync(x => x.UserName == httpContext.User.Identity.Name);
if (user != null)
{
var group = $"{user.OrganizationId}-{location}";
var connection = new Connection { Connected = true, ConnectionId = Context.ConnectionId, Group = group, UserName = user.UserName };
await Groups.AddToGroupAsync(connection.ConnectionId, group);
user.Connections.Add(connection);
db.Users.Update(user);
}
}
await db.SaveChangesAsync();
}
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
if (!string.IsNullOrWhiteSpace(Context.ConnectionId))
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetService<ApplicationDbContext>();
var connection = await db.Connections.Where(x => x.ConnectionId ==
Context.ConnectionId).FirstOrDefaultAsync();
if (connection != null)
{
await Groups.RemoveFromGroupAsync(connection.ConnectionId, connection.Group);
db.Connections.Remove(connection);
await db.SaveChangesAsync();
}
}
}
await base.OnDisconnectedAsync(exception);
}
}
公共类聊天中心:中心
{
私有只读用户管理器_UserManager;
专用readonly IServiceScopeFactory\u serviceScopeFactory;
公共聊天中心(UserManager UserManager、IServiceScopeFactory serviceScopeFactory)
{
_userManager=userManager;
_serviceScopeFactory=serviceScopeFactory;
}
公共异步任务SendAssetGroup(字符串用户名、字符串位置、资产)
{
如果(!string.IsNullOrWhiteSpace(用户名))
{
var user=await\u userManager.Users.Include(x=>x.Connections).SingleAsync(x=>x.UserName==UserName);
如果(用户!=null)
{
var group=$“{user.AccountId}-{location}”;
等待Clients.Group(Group.sendaync(“AssetUpdate”、user.Email、asset”);
}
}
}
公共覆盖异步任务OnConnectedAsync()
{
var httpContext=Context.GetHttpContext();
var location=httpContext.Request.Query[“location”];
使用(var scope=\u serviceScopeFactory.CreateScope())
{
var db=scope.ServiceProvider.GetService();
如果(!string.IsNullOrWhiteSpace(用户名))
{
var user=await db.Users.Include(x=>x.Connections).SingleAsync(x=>x.UserName==httpContext.user.Identity.Name);
如果(用户!=null)
{
var group=$“{user.OrganizationId}-{location}”;
var connection=新连接{Connected=true,ConnectionId=Context.ConnectionId,Group=Group,UserName=user.UserName};
wait Groups.AddToGroupAsync(connection.ConnectionId,group);
user.Connections.Add(连接);
db.Users.Update(用户);
}
}
等待db.saveChangesSync();
}
等待base.OnConnectedAsync();
}
公共覆盖异步任务OnDisconnectedAsync(异常)
{
如果(!string.IsNullOrWhiteSpace(Context.ConnectionId))
{
使用(var scope=\u serviceScopeFactory.CreateScope())
{
var db=scope.ServiceProvider.GetService();
var connection=await db.Connections.Where(x=>x.ConnectionId==
Context.ConnectionId).FirstOrDefaultAsync();
if(连接!=null)
{
wait Groups.RemoveFromGroupAsync(connection.ConnectionId,connection.Group);
db.连接。移除(连接);
等待db.saveChangesSync();
}
}
}
等待base.OnDisconnectedAsync(异常);
}
}
AssetTableChangeService.cs-这里是我需要帮助的地方。当SQLTableDependency检测到资产表的更改时,我需要能够调用AssetHB中的SendAssetToGroup方法。由于用户是组织的一部分,我不想将更新推送到所有组织,我只想将更新发送给特定组织组之外的用户
public class AssetTableChangeService : IAssetTableChangeService
{
private const string TableName = "Assets";
private SqlTableDependency<Asset> _notifier;
private IConfiguration _configuration;
public event AssetChangeDelegate OnAssetChanged;
public StockTableChangeService(IConfiguration configuration)
{
_configuration = configuration;
// SqlTableDependency will trigger an event
// for any record change on monitored table
_notifier = new SqlTableDependency<Asset>(
_configuration.GetConnectionString("DefaultConnection"),
TableName);
_notifier.OnChanged += AssetChanged;
_notifier.Start();
}
private void AssetChanged(object sender, RecordChangedEventArgs<Asset> e)
{
OnAssetChanged.Invoke(this, new AssetChangeEventArgs(e.Entity, e.EntityOldValues));
}
public void Dispose()
{
_notifier.Stop();
_notifier.Dispose();
}
公共类AssetTableChangeService:IAssetTableChangeService
{
私有常量字符串TableName=“资产”;
私有SqlTableDependency\u通知程序;
专用IConfiguration\u配置;
已更改资产的公共事件资产更改委托;
public StockTableChangeService(IConfiguration配置)
{
_配置=配置;
//SqlTableDependency将触发一个事件
//对于监视表上的任何记录更改
_通知程序=新的SqlTableDependency(
_configuration.GetConnectionString(“DefaultConnection”),
表名);
_notifier.OnChanged+=AssetChanged;
_notifier.Start();
}
私有无效资产已更改(对象发送方,RecordChangedEventArgs e)
{
调用(这是新的AssetChangeEventArgs(e.Entity,e.EntityOldValues));
}
公共空间处置()
{
_notifier.Stop();
_Dispose();
}
所以流应该是这样的
public class AssetTableChangeService : IAssetTableChangeService
{
private const string TableName = "Assets";
private SqlTableDependency<Asset> _notifier;
private IConfiguration _configuration;
public event AssetChangeDelegate OnAssetChanged;
public StockTableChangeService(IConfiguration configuration)
{
_configuration = configuration;
// SqlTableDependency will trigger an event
// for any record change on monitored table
_notifier = new SqlTableDependency<Asset>(
_configuration.GetConnectionString("DefaultConnection"),
TableName);
_notifier.OnChanged += AssetChanged;
_notifier.Start();
}
private void AssetChanged(object sender, RecordChangedEventArgs<Asset> e)
{
OnAssetChanged.Invoke(this, new AssetChangeEventArgs(e.Entity, e.EntityOldValues));
}
public void Dispose()
{
_notifier.Stop();
_notifier.Dispose();
}