受欢迎的博客标签

ASP.NET Core SignalR(5):asp.net core 8.0 webapi+signalr(Frpcharp.Signal.Server)

Published

asp.net core 8.0 web api集成signalr

将 SignalR 集成到 ASP.NET Core MVC 程序

 

做了一个在.net core webapi里面集成signalr,我们就可以通过调用webapi来实现服务器向客户端推送消息

第一步引用nuget:Mrcrosoft.AspNetCore.SignalR

 

第二步添加配置代码:

首先Program.cs里面添加如下代码:

           /*    跨源资源共享Cors配置
   跨源资源共享(CORS) 可以用于允许浏览器中的跨源 SignalR 连接。 如果 JavaScript 代码托管在与 SignalR 应用不同的另一个域中,则必须启用 CORS 中间件以允许 JavaScript 连接到 SignalR 应用。 仅允许来自你信任或控制的域的跨源请求。 例如:

   网站托管在 http://www.example.com 上
   SignalR 应用托管在 http://signalr.example.com 上
               应在 SignalR 应用中配置 CORS 以仅允许源 www.example.com。

   有关配置 CORS 的详细信息,请参阅启用跨源请求(CORS)。 SignalR需要以下 CORS 策略:

   允许特定的预期来源。 允许任何来源是可行的,但不安全或不推荐使用。
   必须允许使用 HTTP 方法 GET 和 POST。
   为了使基于 cookie 的粘滞会话正常工作,必须允许使用凭据。 即使未使用身份验证,也必须启用它们。
   但是,在 5.0 中,我们在 TypeScript 客户端中提供了一个不使用凭据的选项。 只有在 100 % 确定应用中不需要 Cookie 之类的凭据时(为粘滞会话使用多个服务器时,Azure 应用服务会使用 cookie),才应使用不使用凭据的选项。

   例如,以下突出显示的 CORS 策略允许 https://example.com 中托管的 SignalR 浏览器客户端访问托管在 https://signalr.example.com 上的 SignalR 应用:
     come from:      https://learn.microsoft.com/zh-cn/aspnet/core/signalr/security?view=aspnetcore-8.0&source=recommendations
            */

           builder.Services.AddCors(options =>
           {
               options.AddPolicy("any",
                   policy => policy.AllowAnyOrigin()
                                   .AllowAnyHeader()
                                   .AllowAnyMethod()
                                   .WithOrigins("http://localhost:5102", "https://iaspnetcore.com")
                                   .AllowCredentials());
           });

more detail:ASP.NET Core 使用 SignalR 遇到的 CORS 问题 https://www.cnblogs.com/myzony/p/10511492.html 

 

然后Program.cs里面添加

  // step 2.register the services required by SignalR hubs
  builder.Services.AddSignalR();

  var app = builder.Build();

 

 //step 1-2 跨域支持
 app.UseCors("any");

 //step 3.configure SignalR endpoints
 app.MapHub<MyHub>("/myhub");

 

然后我们添加一个hubs

 
 
public class SignalrHubs:Hub
    {
        /// <summary>
        /// 创建signalr链接
        /// </summary>
        /// <param name="parentId">pid(作为用户组)</param>
        /// <param name="shopId">sid</param>
        public Task InitUser(string parentId, string shopId)
        {
            Groups.AddAsync(Context.ConnectionId, parentId);
            SignalrGroups.UserGroups.Add(new SignalrGroups()
            {
                ConnectionId = Context.ConnectionId,
                GroupName = parentId,
                ShopId = shopId
            });
            return Clients.All.InvokeAsync("NoticeOnline", "用户组数据更新完成,新增id为:" + Context.ConnectionId + " pid:" + parentId + "   sid:" + shopId + "");
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            //掉线移除用户
            var user = SignalrGroups.UserGroups.FirstOrDefault(c => c.ConnectionId == Context.ConnectionId);
            if (user != null)
            {
                SignalrGroups.UserGroups.Remove(user);
                Groups.RemoveAsync(Context.ConnectionId, user.GroupName);
            }
            return base.OnDisconnectedAsync(exception);
        }
    }
 
 

PS:我这里是根据本人业务需要来做的,大家可以修改成其他的(用户量大的时候内存占用肯定高,这里只做一个简单的例子)

以上基本的环境搭建就已经完成了

接下来控制器里面的代码

 
 
[Produces("application/json")]
    [Route("api/MRSoftPush")]
    public class MRSoftPushController : Controller
    {
        private IHubContext<SignalrHubs> hubContext;
        public MRSoftPushController(IServiceProvider service)
        {
            hubContext = service.GetService<IHubContext<SignalrHubs>>();
        }

        [HttpGet]
        public string Get()
        {
            return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff");
        }

        /// <summary>
        /// 单个connectionid推送
        /// </summary>
        /// <param name="groups"></param>
        /// <returns></returns>
        [HttpPost,Route("AnyOne")]
        public IActionResult AnyOne([FromBody]IEnumerable<SignalrGroups> groups)
        {
            if (groups != null && groups.Any())
            {
                var ids = groups.Select(c=>c.ShopId);
                var list = SignalrGroups.UserGroups.Where(c=>ids.Contains(c.ShopId));
                foreach (var item in list)
                    hubContext.Clients.Client(item.ConnectionId).InvokeAsync("AnyOne", $"{item.ConnectionId}: {item.Content}");
            }
            return Ok();
        }

        /// <summary>
        /// 全部推送
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        [HttpGet,Route("EveryOne")]
        public IActionResult EveryOne(string message)
        {
            hubContext.Clients.All.InvokeAsync("EveryOne", $"{message}");
            return Ok();
        }

        /// <summary>
        /// 组推送
        /// </summary>
        /// <param name="group"></param>
        /// <returns></returns>
        [HttpPost,Route("AnyGroups")]
        public IActionResult AnyGroups([FromBody]SignalrGroups group)
        {
            if (group != null)
            {
                hubContext.Clients.Group(group.GroupName).InvokeAsync("AnyGroups", $"{group.Content}");
            }
            return Ok();
        }

        /// <summary>
        /// 多参数接收方式
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        [HttpGet,Route("MoreParamsRequest")]
        public IActionResult MoreParamsRequest(string message)
        {
            hubContext.Clients.All.InvokeAsync("MoreParamsRequest", message, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"));
            return Ok();
        }
    }
 
 

服务器端的代码到这里全部完成,接下来咱们看客户端的代码

我的客户端代码是在另外一个项目里面,和服务器端是分离的

 
 
<input type="text" id="ParentId" placeholder="ParentId" />
<br />
<input type="text" id="ShopId" placeholder="ShopId" />
<br />
<button id="fuckyou">用户上线</button>
<br />
<br />
<br />

<ul id="message" style="color:red;"></ul>

@section scripts {
    <script>
        $(function () {

            let hubUrl = 'http://192.168.0.149:8009/signalrHubs';
            let httpConnection = new signalR.HttpConnection(hubUrl);
            let hubConnection = new signalR.HubConnection(httpConnection);
            $("#fuckyou").click(function () {
                hubConnection.invoke('InitUser', $("#ParentId").val(), $("#ShopId").val());
            });
            hubConnection.on('NoticeOnline', data => {
                $("#message").append("<li>" + data + "</li>");
            });
            hubConnection.on('EveryOne', data => {
                $("#message").append("<li style=\"color:red;\">全部推送:" + data + "</li>");
            });
            hubConnection.on('AnyGroups', data => {
                $("#message").append("<li style=\"color:black;\">单个用户组推送:" + data + "</li>");
            });
            hubConnection.on('AnyOne', data => {
                $("#message").append("<li style=\"color:blue;\">单个ID推送:" + data + "</li>");
            });
            hubConnection.on('MoreParamsRequest', (message, date) => {
                $("#message").append("<li style=\"color:green;\">多参数接收:" + message + " : " + data + "</li>");
            });
            hubConnection.start();

        });
    </script>
}
复制代码
复制代码

页面上引用连个js

<script src="/js/signalr-client.min.js"></script>
<script src="/js/jquery.min.js"></script>

 

到这里基本就已经完成了,下面看一下运行效果

 

https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-8.0&tabs=visual-studio