我有一个关于 Msmq 和 linq 实体序列化的问题。
我有一个主消息队列和一个错误消息队列。一个进程使用下面的 Send 方法将项目发送到主队列。第二个进程批量接收来自主队列的项目。第二个进程,在异常情况下,将项目发送到错误队列。在此期间,我得到一个 System.ObjectDisposedException 异常。
我正在使用 LINQ-sql,Item 对象是一个可序列化的实体(DataContext 的序列化模式是单向的)。
在 dbml 中,Item 实体与 Source 实体有关联(参见堆栈跟踪中的 Item.get_Source() 行)。我猜测 ObjectDisposedException 异常是在调用 Item 的 Source 的 getter 时发生的。项目的 SourceID 甚至在它被发送到主消息队列之前就被填充了。似乎 LINQ 尝试使用 DataContext 访问该延迟加载的源并抛出 ObjectDisposedException。我不确定将项目发送到主队列与错误队列之间有什么不同。
有任何想法吗?
堆栈跟踪:
System.InvalidOperationException was caught
Message=There was an error generating the XML document.
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o, XmlSerializerNamespaces namespaces)
at System.Messaging.XmlMessageFormatter.Write(Message message, Object obj)
at System.Messaging.Message.AdjustToSend()
at System.Messaging.MessageQueue.SendInternal(Object obj, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
at namespace.Data.ImportServices.Msmq.MsmqProcessor`1.Send(MessageQueue q, List`1 items) in D:\Workspace\namespace.Data\ImportServices\Msmq\MsmqProcessor.cs:line 95
InnerException: System.ObjectDisposedException
Message=Cannot access a disposed object.
Object name: 'DataContext accessed after Dispose.'.
Source=System.Data.Linq
ObjectName=DataContext accessed after Dispose.
StackTrace:
at System.Data.Linq.DataContext.CheckDispose()
at System.Data.Linq.DataContext.GetTable(Type type)
at System.Data.Linq.CommonDataServices.GetDataMemberQuery(MetaDataMember member, Expression[] keyValues)
at System.Data.Linq.CommonDataServices.DeferredSourceFactory`1.ExecuteKeyQuery(Object[] keyValues)
at System.Data.Linq.CommonDataServices.DeferredSourceFactory`1.Execute(Object instance)
at System.Data.Linq.CommonDataServices.DeferredSourceFactory`1.DeferredSource.GetEnumerator()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at System.Data.Linq.EntityRef`1.get_Entity()
at namespace.Data.Item.get_Source() in D:\Workspace\namespace.Data\DB.designer.cs:line 4757
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterItemMsmq.Write25_Item(String n, String ns, Item o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterItemMsmq.Write26_ItemMsmq(String n, String ns, ItemMsmq o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterItemMsmq.Write27_ItemMsmq(Object o)
InnerException:
代码:
将项目发送到队列。
void Send(MessageQueue q, List<T> items)
{
using (q)
{
((XmlMessageFormatter)q.Formatter).TargetTypes = new Type[] { typeof(T) };
foreach (var item in items)
q.Send(item); // <-- ex occurs while sending to Error message queue
}
}
从队列中接收项目并使用回调处理项目。异常时将项目发送到错误队列。
void Receive(MessageQueue q, Action<List<T>> processCallback)
{
List<T> items = null;
try
{
items = GetNextBatchItems(q);
processCallback(items);
}
catch (Exception ex)
{
// sent error messages to the Error queue
var errorQ = _queueFactory.GetErrorQueue(q);
Send(errorQ, items);
}
}
从队列中获取下一批项目。
List<T> GetNextBatchItems(MessageQueue q)
{
var items = new List<T>();
var batchCount = _queueFactory.GetBatchCount(q);
((XmlMessageFormatter)q.Formatter).TargetTypes = new Type[] { typeof(T) };
while (items.Count < batchCount)
{
var message = q.Receive();
if (message.Body is T)
items.Add((T)message.Body);
}
return items;
}