我正在尝试实现一个非常基本的可靠消息状态处理系统,以便在Silverlight到WCF服务器通信中提供更高的可靠性。
我已经采用了将自定义消息头引入SOAP请求的路径,该SOAP请求包含一个递增整数作为消息ID。我的想法是,当我在WCF服务器上收到请求时,我想检查消息ID。如果ID是>最后一个ID,然后我只是执行请求并在请求之后,我将结果的副本与新ID一起缓存。
如果ID是== lastID,我假设客户端从未收到我的消息,我想简单地返回缓存响应对象而不是重新处理请求。我编写了一个MessageInspector Behavior对象,我将其注入到WCF Endpoint行为中。该对象实现了IDispatchMessageInspector,它有两个方法:
object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
// Get the incoming message headers and get the messageId
var idx = request.Headers.FindHeader("ClientRequestId", "");
if (idx >= 0)
{
var requestHeader = request.Headers[idx];
int requestId = 0;
if (Int32.TryParse(requestHeader.ToString(), out requestId))
{
int lastRequest = myCache.GetLastId();
if (requestId <= lastRequest)
{
// @TODO - Send back the saved message
var reply = myCache.GetLastResponse();
if (reply != null)
{
/// ERK -- > Woops, how do I override the service
/// and make the reply here?
}
}
myCache.SetLastId(requestId);
}
}
return null;
}
void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
var requestId = myCache.GetLastId();
if (requestId > 0)
{
myCache.SetLastResponse(reply);
}
}
好吧,我遇到的问题应该是显而易见的...... AfterReceiveRequest返回值(对象)是传递给BeforeSendReply的值为“correlationState”。不,正如我最初预期的那样,请求的新返回值。问题是,我可以阻止消息处理到此位置的服务并返回“缓存”响应吗?
实际上这个问题的更好版本是:这是处理缓存和响应跟踪的适当“注入”位置吗?如果没有,那么“已批准的ms”或更好的方式可以实现此请求跟踪和恢复?
感谢。
-Jeff
答案 0 :(得分:0)
我认为你在这里试图重新发明轮子。 WCF的Reliable Messaging旨在确保邮件传递。我试试,除非你不想出于特定原因使用它吗?
答案 1 :(得分:0)
经过多次试验和磨难后,我找到了解决我的问题的方法,即使不是很优雅,也能解决问题。
为了在检测到重复的服务请求时绕过对服务端点的调用,我只是抛出 FaultException 。然后在 BeforeSendReply 方法中,检查是否 replay.IsFault 然后如果故障是我在 AfterReceiveRequest 中输入的特定故障代码。如果是这样,我将返回消息响应的缓存副本。我需要使用 FaultException 机制来绕过服务调用。
如果有人想要这个解决方案的完整工作代码,请在此处删除注释,并在完成最终调试和单元测试后发布最终代码。
-Jeff