C# 保证消息传递
我正在研究应用程序(托管(web)和安装的windows客户端)之间实时消息的体系结构设计。由于windows客户端安装在客户场所,因此我们无法控制防火墙,即打开任何端口 因此,我考虑使用signar通过http over websocket或回退技术发送实例通知。我们的windows客户端当前使用.Net 4.0框架 我做了一些关于通过信号器保证消息传递的研究,人们建议用GUID确认消息,但不确定我如何实现这个想法。另外,当客户端未连接时,我需要在RabbitMQ上对消息进行排队,onConnected只需从队列发送所有消息C# 保证消息传递,c#,signalr,rabbitmq,C#,Signalr,Rabbitmq,我正在研究应用程序(托管(web)和安装的windows客户端)之间实时消息的体系结构设计。由于windows客户端安装在客户场所,因此我们无法控制防火墙,即打开任何端口 因此,我考虑使用signar通过http over websocket或回退技术发送实例通知。我们的windows客户端当前使用.Net 4.0框架 我做了一些关于通过信号器保证消息传递的研究,人们建议用GUID确认消息,但不确定我如何实现这个想法。另外,当客户端未连接时,我需要在RabbitMQ上对消息进行排队,onConn
namespace SignalRHub.Hubs
{
[Authorize]
public class ChatHub : Hub
{
public void Send(string who, string data)
{
string name = Context.User.Identity.Name;
List<string> groups = new List<string>();
groups.Add(name);
groups.Add(who);
Message message = new Message()
{
messageId = Guid.NewGuid(),
data = data
};
Clients.Groups(groups).addNewMessageToPage(name, JsonConvert.SerializeObject(message));
}
public void AcknowledgeServer(Guid messageId)
{
// Process the message acknowledge
var msgGuid = messageId;
}
public override Task OnConnected()
{
string name = Context.User.Identity.Name;
Groups.Add(Context.ConnectionId, name);
return base.OnConnected();
}
}
public class Message
{
public Guid messageId { get; set; }
public String data { get; set; }
}
}
namespace SignalRHub.Hubs
{
[授权]
公共类聊天室:聊天室
{
公共void发送(字符串who、字符串数据)
{
字符串名称=Context.User.Identity.name;
列表组=新列表();
组。添加(名称);
加上(世卫组织);
消息消息=新消息()
{
messageId=Guid.NewGuid(),
数据=数据
};
Clients.Groups(Groups).addNewMessageToPage(名称,JsonConvert.SerializeObject(消息));
}
公共无效确认服务器(Guid消息ID)
{
//处理消息确认
var msgGuid=messageId;
}
已连接的公用覆盖任务()
{
字符串名称=Context.User.Identity.name;
添加(Context.ConnectionId,name);
返回base.OnConnected();
}
}
公共类消息
{
公共Guid消息ID{get;set;}
公共字符串数据{get;set;}
}
}
请告知?我通过几个步骤就做到了这一点
//just a sample repo : should be persisted, thread safe ...
public static class MessageRepository
{
public static List<Message> UnprocessedMessages = new List<Message>();
public static void AddMessage(Message msg)
{
UnprocessedMessages.Add(msg);
}
public static List<Message> GetMessagesByIssuer(string issuer)
{
return UnprocessedMessages.Where(m => m.Issuer.Equals(issuer)).ToList();
}
public static void Remove(Guid id)
{
if (UnprocessedMessages.Any(m => m.messageId.Equals(id)))
{
var message = UnprocessedMessages.FirstOrDefault(m => m.messageId.Equals(id));
UnprocessedMessages.Remove(message);
}
}
}
[Authorize]
public class ChatHub : Hub
{
public void Send(string who, string data)
{
string name = Context.User.Identity.Name;
List<string> groups = new List<string>();
groups.Add(name);
groups.Add(who);
Message message = new Message()
{
messageId = Guid.NewGuid(),
data = data,
Issuer = name,
Receiver = who,
CreationDate = DateTime.UtcNow
};
MessageRepository.AddMessage(message);
var unProcessedMessages = MessageRepository.GetMessagesByIssuer(name).OrderBy(m => m.CreationDate).ToList();
unProcessedMessages.ForEach(m =>
{
Clients.Groups(groups).addNewMessageToPage(name, JsonConvert.SerializeObject(m));
});
}
public void AcknowledgeServer(Guid messageId)
{
// Process the message acknowledge
var msgGuid = messageId;
MessageRepository.Remove(msgGuid);
}
public override Task OnConnected()
{
string name = Context.User.Identity.Name;
Groups.Add(Context.ConnectionId, name);
return base.OnConnected();
}
}
public class Message
{
public Guid messageId { get; set; }
public String data { get; set; }
public String Issuer { get; set; }
public String Receiver { get; set; }
public DateTime CreationDate { get; set; }
}
//只是一个示例repo:应该是持久的、线程安全的。。。
公共静态类MessageRepository
{
public static List UnprocessedMessages=new List();
公共静态无效添加消息(消息消息消息)
{
未处理的消息。添加(消息);
}
公共静态列表GetMessagesBySuer(字符串颁发者)
{
返回未处理的消息。其中(m=>m.Issuer.Equals(Issuer)).ToList();
}
公共静态无效删除(Guid id)
{
if(UnprocessedMessages.Any(m=>m.messageId.Equals(id)))
{
var message=UnprocessedMessages.FirstOrDefault(m=>m.messageId.Equals(id));
未处理的消息。删除(消息);
}
}
}
[授权]
公共类聊天室:聊天室
{
公共void发送(字符串who、字符串数据)
{
字符串名称=Context.User.Identity.name;
列表组=新列表();
组。添加(名称);
加上(世卫组织);
消息消息=新消息()
{
messageId=Guid.NewGuid(),
数据=数据,
发卡机构=名称,
接收者=谁,
CreationDate=DateTime.UtcNow
};
MessageRepository.AddMessage(message);
var unProcessedMessages=MessageRepository.GetMessagesByIssuer(name).OrderBy(m=>m.CreationDate.ToList();
未处理的消息。ForEach(m=>
{
Clients.Groups(Groups.addNewMessageToPage(名称,JsonConvert.SerializeObject(m));
});
}
公共无效确认服务器(Guid消息ID)
{
//处理消息确认
var msgGuid=messageId;
MessageRepository.Remove(msgGuid);
}
已连接的公用覆盖任务()
{
字符串名称=Context.User.Identity.name;
添加(Context.ConnectionId,name);
返回base.OnConnected();
}
}
公共类消息
{
公共Guid消息ID{get;set;}
公共字符串数据{get;set;}
公共字符串颁发者{get;set;}
公共字符串接收器{get;set;}
公共日期时间创建日期{get;set;}
}
这里有第二种方法(我认为是更好的方法)。您有一个C#客户端单例,它带有一个计时器,定期检查您的存储库,然后发送未处理的消息。您还应该删除过期邮件
public class PresenceMonitor
{
private Timer _timer;
// How often we plan to check if the connections in our store are valid
private readonly TimeSpan _presenceCheckInterval = TimeSpan.FromSeconds(10);
public PresenceMonitor()
{
}
public void StartMonitoring()
{
if (_timer == null)
{
_timer = new Timer(_ =>
{
try
{
Check();
}
catch (Exception ex)
{
// Don't throw on background threads, it'll kill the entire process
Trace.TraceError(ex.Message);
}
},
null,
TimeSpan.Zero,
_presenceCheckInterval);
}
}
private void Check()
{
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
var messages = MessageRepository.GetAllMessages();
messages.ForEach(m =>
{
if (context != null)
{
List<string> groups = new List<string>();
groups.Add(m.Issuer);
groups.Add(m.Receiver);
context.Clients.Groups(groups).addNewMessageToPage(m.Issuer, JsonConvert.SerializeObject(m));
}
});
}
}
公共类呈现监视器
{
私人定时器;
//我们计划多久检查一次商店中的连接是否有效
私有只读时间跨度_presenceCheckInterval=TimeSpan.FromSeconds(10);
公众参与监察
{
}
公共无效开始监视()
{
如果(_timer==null)
{
_计时器=新计时器(=>
{
尝试
{
检查();
}
捕获(例外情况除外)
{
//不要添加后台线程,这会杀死整个进程
Trace.TraceError(例如消息);
}
},
无效的
时间跨度0,
_存在检查间隔);
}
}
私人作废检查()
{
var context=GlobalHost.ConnectionManager.GetHubContext();
var messages=MessageRepository.GetAllMessages();
messages.ForEach(m=>
{
if(上下文!=null)
{
列表组=新列表();
组。添加(m.Issuer);
组。添加(m.Receiver);
上下文客户端