2012-10-23 34 views
9

Tôi đã chuyển đổi một hệ thống khá lớn từ Remoting sang WCF và mọi thứ dường như đang chạy tốt, ngoại trừ chúng tôi thường nhận được ngoại lệ sau: "System.InvalidOperationException: Bộ sưu tập đã được sửa đổi; hoạt động liệt kê có thể không thực thi." Tôi đã không có may mắn theo dõi nó xuống bởi vì nó chỉ xảy ra khi có hàng trăm cuộc gọi nhận được thông qua, và tôi chỉ có thể giả định đó là bởi vì một đối tượng đang được sửa đổi khi nó đang được serialized.Chủ đề DataContractSerilaizer của WCF có an toàn không?

Các lớp học đều sử dụng: [DataContract(IsReference=true)].

Không có ngoại lệ tương tự khi sử dụng tính năng truy cập từ xa, vì vậy tôi tự hỏi liệu có ai có vấn đề tương tự trong WCF hay không hoặc có thể cho tôi biết rằng nó có thể là serializer - trong trường hợp này tôi giả sử tôi phải viết các serializers riêng để thực hiện locks khi cần thiết (đó là một công việc lớn mà tôi muốn tránh).

Sau đây là stack trace:

WCF Error: at System.Collections.Generic.List1.Enumerator.MoveNextRare() at WriteArrayOfLineToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract) at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at WriteLineGroupToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract) at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) at WriteLineToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract) at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph) at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph) at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph) at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer) at System.ServiceModel.Channels.Message.WriteMessage(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota) at System.ServiceModel.Channels.BinaryMessageEncoderFactory.BinaryMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset) at System.ServiceModel.Channels.FramingDuplexSessionChannel.EncodeMessage(Message message) at System.ServiceModel.Channels.FramingDuplexSessionChannel.OnSend(Message message, TimeSpan timeout) at System.ServiceModel.Channels.OutputChannel.Send(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.DuplexChannelBinder.DuplexRequestContext.OnReply(Message message, TimeSpan timeout) at System.ServiceModel.Channels.RequestContextBase.Reply(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.Reply(MessageRpc& rpc)

+5

Đối với những gì nó có giá trị, lỗi, "System.InvalidOperationException: Bộ sưu tập đã được sửa đổi; hoạt động liệt kê có thể không thực thi." rất hiếm khi có bất cứ điều gì để làm với luồng. Nói chung đó là bởi vì bộ sưu tập đã được modfiied trong khi ở giữa đang được liệt kê, đó là khó khăn để repro như 'foreach (var mục trong danh sách) list.Remove (item);'. –

+0

Điều tra của bạn là gì? Tôi đã gặp phải lỗi tương tự này nếu điều tra của tôi đang sử dụng một nguồn tài nguyên được xử lý trước khi tôi thực hiện tuần tự hóa nó. – twreid

+1

@Kirk, nếu trường hợp đó xảy ra, không phải dấu vết ngăn xếp đề xuất rằng nó đang được thực hiện trong serializer, và do đó là một lỗi trong WCF? Tôi tương đối chắc chắn mã của chúng tôi không làm điều đó bất cứ nơi nào như tôi đã thực hiện nó nhiều lần bản thân mình trong quá khứ, do đó, (cuối cùng) nhận thức để xem ra cho nó – user1766568

Trả lời

4

Thật vậy, lỗi này có thể dễ dàng sao chép với DataContractSerializer. Nó không chỉ cho chủ đề an toàn của DataContractSerializer, đó là về chủ đề an toàn của một số bộ sưu tập, được sử dụng trong hợp đồng dữ liệu của bạn:

[DataContract] 
public class C 
{ 
    [DataMember] 
    public List<int> Values { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var c = new C 
     { 
      Values = new List<int>() 
     }; 

     var serializer = new DataContractSerializer(typeof(C)); 

     Task 
      .Factory 
      .StartNew(() => 
      { 
       while (true) 
       { 
        Console.WriteLine("Trying to add new item."); 
        c.Values.Add(DateTime.Now.Millisecond); 
       } 
      }, 
      TaskCreationOptions.LongRunning); 

     Task 
      .Factory 
      .StartNew(() => 
      { 
       while (true) 
       { 
        using (var stream = new MemoryStream()) 
        { 
         Console.WriteLine("Trying to serialize."); 
         serializer.WriteObject(stream, c); 
        } 
       } 
      }, 
      TaskCreationOptions.LongRunning); 

     Console.ReadLine(); 
    } 

Sau thời gian thực hiện ngắn, bạn sẽ nhận được IOE với stack trace tương tự:

at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.List`1.Enumerator.MoveNextRare() at System.Collections.Generic.List`1.Enumerator.MoveNext() at WriteArrayOfintToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract) at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) 

Có vẻ như bạn đang tiếp tục sửa đổi một số dữ liệu được chia sẻ, được lưu trữ cùng một lúc. Bạn có thể bật truy tìm WCF (xem câu hỏi this) để tìm ra thao tác nào gây ra lỗi này và xem xét cẩn thận dữ liệu nào được sử dụng bởi thao tác này.

Sau đó, tùy thuộc vào giá trị của InstanceContextModeConcurrencyMode tính chất của hành vi dịch vụ hiện tại, bạn có thể chọn con đường để đi:

  • hoặc sử dụng một số khóa;
  • hoặc sử dụng bất kỳ bộ sưu tập an toàn theo chủ đề nào;
  • hoặc thay đổi hành vi dịch vụ;
  • hoặc thay đổi bản thân dịch vụ (ví dụ: làm cho nó không trạng thái).
+0

Cảm ơn ví dụ và câu trả lời chi tiết. Hầu hết các dịch vụ là InstanceContextMode.PerCall và ConcurrencyMode.Mulitple, vì vậy tôi có lẽ sẽ đi với một bộ sưu tập thread-an toàn (mà tôi đã không biết) tùy thuộc vào những gì WCF truy tìm cho tôi - trong sự nhầm lẫn của tôi, tôi hoàn toàn quên về truy tìm , mặc dù không có sự giải thích của bạn, vẫn sẽ không biết những giải pháp tốt nhất. Cảm ơn! – user1766568

+0

@ user1766568: Tôi hy vọng, bạn sẽ không thay thế mọi bộ sưu tập thành chất tương tự an toàn theo chủ đề của nó, bởi vì nó là một cách để địa ngục. – Dennis

1

Nếu giả thuyết của Dennis là chính xác thì cách sạch nhất để giải quyết vấn đề này là sao chép bộ sưu tập và gửi bản sao qua dây. Tại thời điểm đó, nó không quan trọng nếu bản gốc được sửa đổi trong quá trình serialization

+0

Cảm ơn bạn đã phản hồi. Có thể là dễ nhất, nhưng đồ thị đối tượng có thể khá sâu, vì vậy tôi không chắc nó sẽ là nhanh nhất trong trường hợp cụ thể này. Tôi sẽ trả về một đối tượng có thể có một bộ sưu tập, hoặc có một bộ sưu tập các đối tượng với các bộ sưu tập, etc.etc. vì vậy tôi nghĩ rằng tôi có thể phải đi với các bộ sưu tập an toàn chỉ. – user1766568

+0

Nó không phải là một giả thuyết. :) Bạn có thể biên dịch mẫu mã để đảm bảo nó. – Dennis

+0

Tôi không nói rằng mã của bạn không chứng minh được vấn đề - điều tôi đang nói chỉ vì mã của bạn có cùng một triệu chứng không có nghĩa là nó cũng giống như nguyên nhân OP. Tuy nhiên nếu mã của bạn là cùng một nguyên nhân thì sao chép là một cách sạch sẽ để giải quyết vấn đề –

Các vấn đề liên quan