You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Asp.Net Core 8.0分层架构中SignalR与SqlDependency使用咨询

Asp.Net Core 8.0分层架构中SignalR+SqlDependency实现方案

一、能否与Entity Framework或Dapper ORM配合使用?

完全可以,两种ORM都能适配SqlDependency的使用场景:

  • EF Core:可以通过FromSqlRaw执行原生查询来关联SqlDependency,或者直接获取EF上下文底层的SqlConnection对象进行操作。需要注意EF上下文的生命周期,确保监听期间连接状态有效,或者在SqlDependency触发后重新建立监听。
  • Dapper:作为轻量ADO.NET封装,直接基于SqlConnection创建SqlDependency的方式和原生ADO.NET完全一致,灵活性更高,不需要额外适配。

二、分层架构下的具体实现步骤

1. 前置准备:数据库与EntityLayer

  • 确保SQL Server数据库开启Service Broker,执行SQL命令:ALTER DATABASE [你的数据库名] SET ENABLE_BROKER;
  • 在EntityLayer定义与数据库表对应的实体类,比如Order、Product等。

2. DataAccessLayer(DAL)实现

  • 定义仓储接口,包含数据查询和SqlDependency注册方法:
    public interface IRealTimeRepository<T> where T : class
    {
        Task<IEnumerable<T>> GetAllAsync();
        void RegisterDataChangeNotification(Action<SqlNotificationEventArgs> onChange);
    }
    
  • 实现仓储类(以Dapper为例):
    public class RealTimeRepository<T> : IRealTimeRepository<T>
    {
        private readonly string _connStr;
    
        public RealTimeRepository(IConfiguration config)
        {
            _connStr = config.GetConnectionString("DefaultConnection");
        }
    
        public async Task<IEnumerable<T>> GetAllAsync()
        {
            using var conn = new SqlConnection(_connStr);
            return await conn.QueryAsync<T>($"SELECT * FROM {typeof(T).Name}s");
        }
    
        public void RegisterDataChangeNotification(Action<SqlNotificationEventArgs> onChange)
        {
            using var conn = new SqlConnection(_connStr);
            conn.Open();
            using var cmd = new SqlCommand($"SELECT Id FROM {typeof(T).Name}s", conn);
            cmd.Notification = null;
    
            var dependency = new SqlDependency(cmd);
            dependency.OnChange += (sender, e) =>
            {
                onChange.Invoke(e);
                // 重新注册监听,因为SqlDependency触发一次后自动失效
                RegisterDataChangeNotification(onChange);
            };
            cmd.ExecuteNonQuery();
        }
    }
    

3. BusinessLayer(BLL)实现

  • 定义业务服务接口,封装数据转换和事件通知逻辑:
    public interface IRealTimeDataService
    {
        Task<IEnumerable<YourDto>> GetLatestDataAsync();
        event Action OnDataChanged; // 定义事件供API层Hub订阅
    }
    
  • 实现业务服务,关联DAL并触发事件:
    public class RealTimeDataService : IRealTimeDataService
    {
        private readonly IRealTimeRepository<YourEntity> _repo;
        private readonly IMapper _mapper;
    
        public event Action OnDataChanged;
    
        public RealTimeDataService(IRealTimeRepository<YourEntity> repo, IMapper mapper)
        {
            _repo = repo;
            _mapper = mapper;
            // 注册SqlDependency监听
            _repo.RegisterDataChangeNotification(e =>
            {
                if (e.Type == SqlNotificationType.Change)
                {
                    OnDataChanged?.Invoke();
                }
            });
        }
    
        public async Task<IEnumerable<YourDto>> GetLatestDataAsync()
        {
            var entities = await _repo.GetAllAsync();
            return _mapper.Map<IEnumerable<YourDto>>(entities);
        }
    }
    

4. DtosLayer

  • 定义与实体类对应的DTO,比如YourDto,用于API和UI层数据传输,避免直接暴露实体结构。

5. ApiLayer(SignalR Hub + 接口配置)

  • 安装Microsoft.AspNetCore.SignalR NuGet包
  • 创建SignalR Hub类,订阅BLL事件并推送数据给客户端:
    public class DataUpdateHub : Hub
    {
        private readonly IRealTimeDataService _dataService;
    
        public DataUpdateHub(IRealTimeDataService dataService)
        {
            _dataService = dataService;
            _dataService.OnDataChanged += async () =>
            {
                var latestData = await _dataService.GetLatestDataAsync();
                await Clients.All.SendAsync("ReceiveDataUpdate", latestData);
            };
        }
    }
    
  • 在Program.cs中配置SignalR和依赖注入:
    // 注册服务
    builder.Services.AddSignalR();
    builder.Services.AddScoped(typeof(IRealTimeRepository<>), typeof(RealTimeRepository<>));
    builder.Services.AddScoped<IRealTimeDataService, RealTimeDataService>();
    builder.Services.AddAutoMapper(typeof(Program));
    
    // 配置中间件
    app.MapHub<DataUpdateHub>("/dataUpdateHub");
    // 可选:提供REST接口供UI主动拉取数据
    app.MapGet("/api/realtime/data", async (IRealTimeDataService service) =>
    {
        var data = await service.GetLatestDataAsync();
        return Results.Ok(data);
    });
    

6. UI Layer(MVC)实现

  • 安装Microsoft.AspNetCore.SignalR.Client NuGet包
  • 在视图中引入SignalR客户端脚本,并编写连接逻辑:
    <div id="dataList"></div>
    
    <script src="~/lib/signalr/dist/browser/signalr.js"></script>
    <script>
        // 建立与API层Hub的连接
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/dataUpdateHub")
            .build();
    
        // 接收API推送的更新数据
        connection.on("ReceiveDataUpdate", (data) => {
            renderData(data);
        });
    
        // 页面加载时主动拉取初始数据
        async function loadInitialData() {
            const res = await fetch("/api/realtime/data");
            const data = await res.json();
            renderData(data);
        }
    
        // 渲染数据到页面
        function renderData(data) {
            let html = "<ul>";
            data.forEach(item => {
                html += `<li>ID: ${item.Id} | 名称: ${item.Name}</li>`;
            });
            html += "</ul>";
            document.getElementById("dataList").innerHTML = html;
        }
    
        // 启动连接
        connection.start().catch(err => console.error(err));
        loadInitialData();
    </script>
    

内容的提问来源于stack exchange,提问作者Gökmen Ada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:26:01