9

かなり大規模なシステムをRemotingからWCFに変換してきましたが、「System.InvalidOperationException:コレクションが変更されました。列挙操作が実行されない可能性があります。」という例外が頻繁に発生することを除いて、すべてが正常に実行されているようです。何百もの呼び出しが通過したときにのみ発生するため、追跡することができませんでした。これは、オブジェクトがシリアル化されているときに変更されているためだと推測できます。

すべてのクラスが使用します:[DataContract(IsReference=true)]

リモーティングを使用するときに同様の例外はなかったので、誰かがWCFで同様の問題を抱えているのか、それともおそらくシリアライザーであるかを知らせてくれるのだろうかと思います。その場合、実行するには独自のシリアライザーを作成する必要があると思います。locks必要に応じて(これは避けたい大きな仕事です)。

スタックトレースは次のとおりです。

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)

4

2 に答える 2

5

実際、このエラーは で簡単に再現できますDataContractSerializer。のスレッド セーフについては言及していませんDataContractSerializer。データ コントラクトで使用されるコレクションのスレッド セーフについてです。

[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();
    }

短い実行時間の後、同様のスタック トレースで IOE を取得します。

   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)

同時にシリアル化されている共有データを変更し続けているようです。WCF トレース (この質問を参照) を有効にして、このエラーの原因となった操作を特定し、この操作で使用されているデータを注意深く調べることができます。

次に、現在のサービス動作のInstanceContextModeおよびConcurrencyModeプロパティの値に応じて、どちらに進むかを選択できます。

  • 何らかのロックを使用するか。
  • またはスレッドセーフなコレクションを使用する。
  • またはサービスの動作を変更する。
  • または、サービス自体を変更する (たとえば、ステートレスにする)。
于 2012-10-23T05:37:40.807 に答える
1

Dennis の仮説が正しければ、これを解決する最もクリーンな方法は、コレクションをコピーし、そのコピーをネットワーク経由で送信することです。その時点で、連載中にオリジナルが変更されても問題ありません。

于 2012-10-23T07:56:11.930 に答える