linq 엔터티의 Msmq 및 serialization 관련 질문이 있습니다.MSMQ 및 LINQ 엔터티 개체 직렬화 예외
기본 MessageQueue와 오류 MessageQueue가 있습니다. 한 프로세스는 아래 Send 메서드를 사용하여 항목을 Primary 큐로 보냅니다. 두 번째 프로세스는 일차 큐에서 항목을 일괄 적으로받습니다. 두 번째 프로세스 (예외시)는 항목을 오류 대기열로 보냅니다. 이 동안 System.ObjectDisposedException 예외가 발생합니다.
저는 LINQ-sql을 사용하고 Item 객체는 직렬화 가능한 엔티티입니다 (DataContext의 직렬화 모드는 단방향 임).
dbml에서 Item 엔티티는 Source 엔티티에 대한 연결을 갖습니다 (Stacktrace의 Item.get_Source() 행 참조). 항목의 소스 getter가 호출 될 때 ObjectDisposedException 예외가 발생합니다. Item의 SourceID는 Primary MessageQueue로 전송되기 전에 채워집니다. LINQ는 DataContext를 사용하여 지연로드 된 소스에 액세스하려고 시도하고 ObjectDisposedException을 throw합니다. 기본 대기열과 오류 대기열에 항목을 보내는 것의 차이점을 잘 모르겠습니다.
아이디어가 있으십니까?
스택 트레이스 :
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);
}
}
다음 배치 항목을 대기열에서 가져옵니다. 의 직렬화 후크가 LINQ - 투 - SQL은 DataContractSerializer를위한 것입니다 때, XmlSerializer를를 사용하고 있기 때문에 나는이 의심
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;
}
나는 100 % 동의하여 직렬화 된 모델을 최소화하고, 바람직하게는 DB 엔티티를 전혀 사용하지 않습니다. 이를 통해 직렬화에 대해 (DB 모델을 오염시키지 않으면 서) 이해할 수있는 방식으로 주석을 달고 간단하게 유지할 수 있습니다. –
DataContractSerializer를 사용하여 예외가 없으므로이 문제를 해결할 것입니다. 완전로드는 옵션이지만 원하는 것은 아닙니다. 무거운 LINQ 엔터티 개체 대신 POCO 더미 개체를 사용하는 장점을 알고있었습니다. 그러나 나는 이것을 시험해보고 싶었다. – hIpPy