C# MSMQ和LINQ实体对象序列化异常

C# MSMQ和LINQ实体对象序列化异常,c#,linq,serialization,msmq,C#,Linq,Serialization,Msmq,我有一个关于Msmq和linq实体序列化的问题 我有一个主消息队列和一个错误消息队列。一个进程使用下面的发送方法将项目发送到主队列。第二个进程从主队列批量接收项目。第二个进程在出现异常时,将项目发送到错误队列。在此期间,我得到一个System.ObjectDisposedException异常 我使用的是LINQSQL,项对象是一个可序列化的实体(DataContext的序列化模式是单向的) 在dbml中,项实体与源实体有关联(请参阅stacktrace中的Item.get_Source()行)

我有一个关于Msmq和linq实体序列化的问题

我有一个主消息队列和一个错误消息队列。一个进程使用下面的发送方法将项目发送到主队列。第二个进程从主队列批量接收项目。第二个进程在出现异常时,将项目发送到错误队列。在此期间,我得到一个System.ObjectDisposedException异常

我使用的是LINQSQL,项对象是一个可序列化的实体(DataContext的序列化模式是单向的)

在dbml中,项实体与源实体有关联(请参阅stacktrace中的Item.get_Source()行)。我猜ObjectDisposedException异常是在调用项的源getter时发生的。项目的SourceID甚至在发送到主MessageQueue之前就已填充。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发送(MessageQueue q,列表项)
{
使用(q)
{
(XmlMessageFormatter)q.Formatter.TargetTypes=新类型[]{typeof(T)};
foreach(项目中的var项目)

q、 Send(item);//我怀疑这是因为您使用的是XmlSerializer,而LINQ to SQL中的序列化挂钩是针对DataContractSerializer的。区别在于后者支持序列化前/后回调,用于帮助禁用级联加载

我怀疑串行化会导致导航属性在串行化器爬行的过程中缓慢加载。使用DATACONTRATCTRORALIZER会避免这种情况。 如果模型尝试延迟加载,但基础连接/数据上下文不再可用,则它将失败

另一个更好的方法:

不要序列化延迟加载等复杂模型


相反,在我看来,使用您的数据上下文来填充一个愚蠢、无知的普通POCO/DTO模型,它什么也不知道,什么也不做,只是充当一个非常容易序列化的简单数据。根据我的经验,这种方法工作得更好(在序列化方面,这是一个不小的经验)。作为一个附带好处,因为这将是您的POCO/DTO,您可以轻松地将其配置为适合您喜欢的任何序列化程序。

我怀疑这是因为您使用的是XmlSerializer,而LINQ to SQL中的序列化挂钩是针对DataContractSerializer的。区别在于后者支持预/后序列化调用backs,用于帮助禁用级联加载

我怀疑串行化会导致导航属性在串行化器爬行的过程中缓慢加载。使用DATACONTRATCTRORALIZER会避免这种情况。 如果模型尝试延迟加载,但基础连接/数据上下文不再可用,则它将失败

另一个更好的方法:

不要序列化延迟加载等复杂模型


相反,在我看来,使用您的数据上下文来填充一个愚蠢、无知的普通POCO/DTO模型,它什么也不知道,什么也不做,只是充当一个非常容易序列化的简单数据。根据我的经验,这种方法工作得更好(在序列化方面,这是一个不小的经验)。作为一个附带的好处,因为这将是您的POCO/DTO,您可以轻松地将其配置为适合您喜欢的任何序列化程序。

我100%同意将序列化模型最小化,最好不要使用您的DB实体。这使您可以以对序列化有意义的方式对它们进行注释(同时不会污染您的DB模型)在保持简单的同时,我使用DataContractSerializer不会出现异常,因此我将继续。完全加载是一个选项,但我不想这样做。我知道使用POCO虚拟对象而不是重型LINQ实体对象的优点。但我想尝试一下。我100%同意将序列化模型最小化,最好不要使用y我们的数据库实体。这让您可以用一种对序列化有意义的方式对它们进行注释(同时不会污染您的数据库模型)在保持简单的同时,我使用DataContractSerializer不会出现异常,因此我将继续。完全加载是一个选项,但我不想这样做。我知道使用POCO虚拟对象而不是重型LINQ实体对象的优点。但我想尝试一下。
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;
}