Msmqとlinqエンティティのシリアル化について質問があります。
プライマリメッセージキューとエラーメッセージキューがあります。1つのプロセスは、以下のSendメソッドを使用してアイテムをプライマリキューに送信します。2番目のプロセスは、プライマリキューからアイテムをバッチで受け取ります。2番目のプロセスは、例外として、アイテムをエラーキューに送信します。この間に、System.ObjectDisposedException例外が発生します。
LINQ-sqlを使用していますが、Itemオブジェクトはシリアル化可能なエンティティです(DataContextのシリアル化モードは単方向です)。
dbmlでは、ItemエンティティはSourceエンティティに関連付けられています(スタックトレースのItem.get_Source()行を参照してください)。アイテムのソースのゲッターが呼び出されたときにObjectDisposedException例外が発生すると推測しています。アイテムの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;
}