创建控制台应用程序启动SignalR服务
using Microsoft.AspNet.SignalR;
using Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using System;
using System.Reflection;
using System.Configuration;
using log4net;
namespace SignalRServer
{
public class Startup
{
public static ILog log = LogManager.GetLogger("SignalR Server Log");
/// <summary>
/// 开启服务
/// </summary>
public static void Start()
{
//string SignalRURI = @"https://localhost:44342/";
string SignalRURI = ConfigurationManager.AppSettings["SignalRServerUrl"].ToString().Trim();
try
{
log4net.Config.XmlConfigurator.Configure();
try
{
using (WebApp.Start(SignalRURI, builder =>
{
builder.Map("/signalr", map =>
{
// Setup the cors middleware to run before SignalR.
// By default this will allow all origins. You can
// configure the set of origins and/or http verbs by
// providing a cors options with a different policy.
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
// You can enable JSONP by uncommenting line below.
// JSONP requests are insecure but some older browsers (and some
// versions of IE) require JSONP to work cross domain
EnableJSONP = true
};
// Run the SignalR pipeline. We're not using MapSignalR
// since this branch is already runs under the "/signalr"
// path.
map.RunSignalR(hubConfiguration);
});
builder.MapSignalR();
}))
{
Console.WriteLine("服务开启成功,运行在{0}", SignalRURI);
log.Info($"服务开启成功,运行在{SignalRURI}");
Console.ReadLine();
}
}
catch (TargetInvocationException)
{
Console.WriteLine("服务开启失败. 已经有一个服务运行在{0}", SignalRURI);
log.Error($"服务开启失败. 已经有一个服务运行在{SignalRURI}");
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine("服务开启异常:{0}", ex.ToString());
log.Error($"服务开启异常:{ex}");
Console.ReadLine();
}
}
}
}
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System;
using System.Threading.Tasks;
namespace SignalRServer
{
/// <summary>
/// 即使通信服务(可供客户端调用的方法开头用小写)
/// </summary>
[HubName("ChatsHub")]
public class Chats : Hub
{
#region 重载Hub方法
/// <summary>
/// 建立连接
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
AddOnline();
return base.OnConnected();
}
/// <summary>
/// 断开连接
/// </summary>
/// <param name="stopCalled">是否是客户端主动断开:true是,false超时断开</param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
RemoveOnline();
return base.OnDisconnected(stopCalled);
}
/// <summary>
/// 重新建立连接
/// </summary>
/// <returns></returns>
public override Task OnReconnected()
{
AddOnline();
return base.OnReconnected();
}
#endregion
#region 私有方法
/// <summary>
/// 添加在线用户
/// </summary>
private void AddOnline()
{
string clientId = Context.ConnectionId;
string userId = GetUserId();
Groups.Add(clientId, userId);
Console.WriteLine($"ClientId:{clientId} UserId:{userId} AddOnline");
Startup.log.Info($"ClientId:{clientId} UserId:{userId} AddOnline");
}
/// <summary>
/// 移除在线用户
/// </summary>
private void RemoveOnline()
{
string clientId = Context.ConnectionId;
string userId = GetUserId();
Groups.Remove(clientId, userId);
Console.WriteLine($"ClientId:{clientId} UserId:{userId} RemoveOnline");
Startup.log.Info($"ClientId:{clientId} UserId:{userId} RemoveOnline");
}
/// <summary>
/// 获取登录用户Id
/// </summary>
/// <returns></returns>
private string GetUserId()
{
string userId = "";
if (Context.QueryString["UserId"] != null)
{
userId = Context.QueryString["UserId"];
}
return userId;
}
#endregion
#region 客户端操作
/// <summary>
/// 根据接收方客户端id发送消息
/// </summary>
/// <param name="sendUserId">发送方Id</param>
/// <param name="revUserId">接收方Id,多客户端Id相同则都收到信息</param>
/// <param name="msg">消息</param>
/// <param name="time">发送时间</param>
/// <param name="isSysMsg">是否系统消息</param>
public void SendMsgByUserId(string sendUserId, string revUserId, string msg, DateTime time, bool isSysMsg)
{
Clients.Group(revUserId).RevMsg(sendUserId, msg, time, isSysMsg);
Console.WriteLine($"{time} isSysMsg:{isSysMsg} Id:{sendUserId} Send To Id:{revUserId} Msg:{msg}");
Startup.log.Info($"{time} isSysMsg:{isSysMsg} Id:{sendUserId} Send To Id:{revUserId} Msg:{msg}");
}
/// <summary>
/// 向所有客户端发送消息
/// </summary>
/// <param name="sendUserId">发送方Id</param>
/// <param name="msg">消息</param>
/// <param name="time">发送时间</param>
/// <param name="isSysMsg">是否系统消息</param>
public void SendMsgAll(string sendUserId, string msg, DateTime time, bool isSysMsg)
{
this.Clients.All.RevMsg(sendUserId, msg, time, isSysMsg);
Console.WriteLine($"{time} isSysMsg:{isSysMsg} Id:{sendUserId} Send Msg:{msg}");
Startup.log.Info($"{time} isSysMsg:{isSysMsg} Id:{sendUserId} Send Msg:{msg}");
}
#endregion
}
}
客户端操作类封装
using Microsoft.AspNet.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SignalRClientTest
{
public class HubClient
{
public Action<string> ConnectionError;//连接异常委托
public event EventHandler<RevMsgAllEventArgs> RevMsgAllEvent;//消息接收事件
private readonly HubConnection hubConnection;
private readonly IHubProxy hubProxy;
public string UserId { get; set; }
/// <summary>
/// HubClient构造函数
/// </summary>
/// <param name="signalrUrl">SignalR服务地址</param>
/// <param name="hubName">通信服务名称</param>
/// <param name="queryString">通信客户端ID查询字符串,多客户端ID相同则同组获取信息</param>
public HubClient(string signalrUrl, string hubName, string queryString)
{
hubConnection = new HubConnection(signalrUrl, new Dictionary<string, string>() { { "UserId", queryString } });
hubProxy = hubConnection.CreateHubProxy(hubName);
UserId = queryString;
hubConnection.Error += (Exception) => { ConnectionError?.Invoke("HubConnection Fail. " + Exception.Message); };//连接异常
}
/// <summary>
/// 连接测试
/// </summary>
public bool StartTest()
{
try
{
this.hubConnection.Start().Wait();
this.hubConnection.Dispose();//使用Stop()关闭连接在Start()和Stop()连续切换的时候可能异常
return true;
}
catch (Exception ex)
{
ConnectionError?.Invoke("HubConnection Start Test Fail. " + ex.Message);//连接测试异常
}
return false;
}
/// <summary>
/// 开启连接
/// </summary>
public void Start()
{
if (this.hubConnection.State != ConnectionState.Connected)
{
if (StartTest())
hubConnection.Start();
}
}
/// <summary>
/// 关闭连接
/// </summary>
public void Stop()
{
if (this.hubConnection.State == ConnectionState.Connected)
hubConnection.Dispose();//使用Stop()关闭连接在Start()和Stop()连续切换的时候可能异常
}
/// <summary>
/// 调用hub方法
/// </summary>
/// <param name="methodName">SignalR服务方法</param>
/// <param name="args">SignalR服务方法参数</param>
public void CallMethod(string methodName, params object[] args)
{
if (this.hubConnection.State == ConnectionState.Connected)
hubProxy.Invoke(methodName, args);
}
public void RevMsg()
{
this.hubProxy.On("RevMsg",
(string sendId, string msg, DateTime time, bool isSyaMsg) =>
{
RevMsgAllEvent?.Invoke(this, new RevMsgAllEventArgs(sendId, msg, time, isSyaMsg));
});
}
}
public class RevMsgAllEventArgs : EventArgs
{
public RevMsgAllEventArgs(string sendId, string msg, DateTime time, bool isSyaMsg)
{
this.SendId = sendId;
this.Msg = msg;
this.Time = time;
this.IsSysMsg = isSyaMsg;
}
public string SendId { get; private set; }
public string Msg { get; private set; }
public DateTime Time { get; private set; }
public bool IsSysMsg { get; private set; }
}
}