收集被修改;枚举操作可能无法执行。但为什么呢?

时间:2016-06-15 20:07:42

标签: asp.net json serialization

所有

我收到"收藏被修改;枚举操作可能无法执行。"在我的对象图的序列化过程中(它在SerializeDictionary()上失败了,但是我的对象图中没有字典)。我正在使用Newtonsoft序列化来序列化我的对象图。

我知道异常意味着什么,在查看我的对象图后,我想在Newtonsoft json序列化程序中可能存在一个错误。下面我发布了整个堆栈跟踪。这是有趣的细节。我设置了另一个测试用例来解决问题,令我惊讶的是我没有收到序列化异常。相同的对象图,相同的序列化程序,只是不同的项目环境。以下是2个案例,1个作品,其他不起作用。在这两种情况下,我都从数据库加载精确的对象图形!

案例1:序列化失败

Visual Studio:2012专业版

asp.net 3.5(CLR 2)

Serializer:Newtonsoft

项目类型:Web应用程序

案例2:序列化工作

Visual Studio:2005 Pro

asp.net 2.0(CLR 2)

Serializer:Newtonsoft

项目类型:控制台应用

序列化代码:

    Receipt rec = ReceiptManager.LoadReceipt(26157);
var result = Newtonsoft.Json.JsonConvert.SerializeObject(rec,
                      new Newtonsoft.Json.JsonSerializerSettings
                      {
                          settings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
                      });

模型(看你能否发现错误):

namespace PrlSystems.PimarcCore.DomainModel.Commerce
{
    /// <summary>
    /// Represents a document in accounting.
    /// </summary>
    [Serializable()]
    public class Document
    {
        private string _documentNumber = "";
        private DateTime _documentDate;
        private string _currencyCode;


        public Document()
        {
        }

        public Document(string documentNumber)
        {
            _documentNumber = documentNumber;
        }

        public string DocumentNumber
        {
            get { return _documentNumber; }
            set { _documentNumber = value; }
        }

        public DateTime DocumentDate
        {
            get { return _documentDate; }
            set { _documentDate = value; }
        }

        public string CurrencyCode
        {
            get { return _currencyCode; }
            set { _currencyCode = value; }
        }
    }
}



namespace PrlSystems.PimarcCore.DomainModel.Commerce
{
    [Serializable()]
    public class Receipt : Document
    {
        private int _id;
        private long _versionNumber;

        private ProjectInfo _project;
        private ClientInfo _client;
        private PaymentMethod _paymentMethod;
        private string _referenceNo;
        private string _chequeNo;
        private Money _amountReceived;
        private string _comment;
        private string _templateFile;   // used to render this document (ie. read-only/printing)

        // accounting export related
        private bool _posted;
        private string _accountingId; //  The internal id of the payment as it is in the accounting system.
        private string _accountingBatchId;
        private DateTime? _transactionDate;
        private string _transactionId;
        private int? _transactionNumber;
        private PostingStatus? _postStatus;
        private string _postingUser;    // user name that posted this document

        private ReceiptLineItemCollection _lineItems = new ReceiptLineItemCollection();

        public Receipt()
        {
            _id = -1;
        }

        public Receipt(string currencyCode)
        {
            _id = -1;
            CurrencyCode = currencyCode;
        }

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public long VersionNumber
        {
            get { return _versionNumber; }
            set { _versionNumber = value; }
        }

        public ProjectInfo Project
        {
            get { return _project; }
            set { _project = value; }
        }

        public ClientInfo Client
        {
            get { return _client; }
            set { _client = value; }
        }

        public PaymentMethod PaymentMethod
        {
            get { return _paymentMethod; }
            set { _paymentMethod = value; }
        }

        public string ReferenceNo
        {
            get { return _referenceNo; }
            set { _referenceNo = value; }
        }

        public string ChequeNo
        {
            get { return _chequeNo; }
            set { _chequeNo = value; }
        }

        public Money AmountReceived
        {
            get { return _amountReceived; }
            set { _amountReceived = value; }
        }

        public string Comment
        {
            get { return _comment; }
            set { _comment = value; }
        }

        public string TemplateFile
        {
            get { return _templateFile; }
            set { _templateFile = value; }
        }



        public bool Posted
        {
            get { return _posted; }
            set { _posted = value; }
        }

        public string AccountingId
        {
            get { return _accountingId; }
            set { _accountingId = value; }
        }

        public string AccountingBatchId
        {
            get { return _accountingBatchId; }
            set { _accountingBatchId = value; }
        }

        public DateTime? TransactionDate
        {
            get { return _transactionDate; }
            set { _transactionDate = value; }
        }

        public string TransactionId
        {
            get { return _transactionId; }
            set { _transactionId = value; }
        }

        public int? TransactionNumber
        {
            get { return _transactionNumber; }
            set { _transactionNumber = value; }
        }

        public PostingStatus? PostStatus
        {
            get { return _postStatus; }
            set { _postStatus = value; }
        }

        public string PostingUser
        {
            get { return _postingUser; }
            set { _postingUser = value; }
        }

        public ReceiptLineItemCollection LineItems
        {
            get { return _lineItems; }
            set { _lineItems = value; }
        }

        public ReceiptLineItem FindReceiptLine(int invoiceId)
        {
            foreach (ReceiptLineItem lineItem in _lineItems)
            {
                if (lineItem.Invoice.Id == invoiceId)
                    return lineItem;
            }
            return null;
        }

    }
}





namespace PrlSystems.PimarcCore.DomainModel.Commerce
{
    public class ReceiptLineItemCollection : List<ReceiptLineItem>
    {
    }
}








namespace PrlSystems.PimarcCore.DomainModel.Commerce
{
    public class ReceiptLineItem
    {
        private InvoiceDetailedSummary _invoice;
        private Money _amountAppliedToInvoice;

        private Receipt _receipt;

        public ReceiptLineItem()
        {
        }

        public ReceiptLineItem(Receipt receipt)
        {
            if (receipt == null)
                throw new ArgumentNullException("receipt");
            _receipt = receipt;
        }

        public InvoiceDetailedSummary Invoice
        { 
            get { return _invoice; }
            set { _invoice = value; } 
        }

        public Money AmountAppliedToInvoice
        { 
            get { return _amountAppliedToInvoice; }
            set { _amountAppliedToInvoice = value; }
        }

        [Obsolete("TODO: To be removed in future release.")]
        public Receipt Receipt
        {
            get { return _receipt; }
            set { _receipt = value; }
        }
    }
}












namespace PrlSystems.PimarcCore.DomainModel.Commerce
{
    /// <summary>
    /// Lightweight object that contains brief invoice summary.
    /// </summary>
    [Serializable()]
    public class InvoiceBriefSummary
    {
        public const string PROP_INVOICEID = "Id";
        public const string PROP_INVOICEDATE = "InvoiceDate";
        public const string PROP_INVOICENUMBER = "InvoiceNumber";
        public const string PROP_CURRENCYCODE = "CurrencyCode";
        public const string PROP_GRANDTOTAL = "GrandTotal";

        private int _id;
        private DateTime _invoiceDate;
        private string _invoiceNumber;
        private string _currencyCode;

        public InvoiceBriefSummary()
        {
        }

        public InvoiceBriefSummary(Invoice invoice)
        {
            if (invoice == null)
                throw new ArgumentNullException("invoice");

            _id = invoice.Id;
            _invoiceDate = invoice.DocumentDate;
            _invoiceNumber = invoice.DocumentNumber;
            _currencyCode = invoice.CurrencyCode;
        }

        public InvoiceBriefSummary(InvoiceHeader invoice)
        {
            if (invoice == null)
                throw new ArgumentNullException("invoice");

            _id = invoice.Id;
            _invoiceDate = invoice.InvoiceDate;
            _invoiceNumber = invoice.InvoiceNumber;
            _currencyCode = invoice.CurrencyCode;            
        }

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public DateTime InvoiceDate
        {
            get { return _invoiceDate; }
            set { _invoiceDate = value; }
        }

        public string InvoiceNumber
        {
            get { return _invoiceNumber; }
            set { _invoiceNumber = value; }
        }

        public string CurrencyCode
        {
            get { return _currencyCode; }
            set { _currencyCode = value; }
        }
    }
}






namespace PrlSystems.PimarcCore.DomainModel.Commerce
{
    /// <summary>
    /// XML serializer friendly detailed invoice summary.
    /// </summary>
    [Serializable()]
    public class InvoiceDetailedSummary : InvoiceBriefSummary
    {
        private ContactInfo _billTo;
        private ProjectInfo _project;
        private decimal _subtotal;
        private decimal _grandtotal;
        private decimal _taxtotal;

        private string _accountingId;
        private string _transactionId;
        private int? _transactionNumber;

        public InvoiceDetailedSummary()
        {
        }

        public InvoiceDetailedSummary(Invoice invoice)
            : base(invoice)
        {
            _billTo = invoice.BillToAddress;
            _project = invoice.Project;
            _subtotal = invoice.Subtotal.Amount;

            TaxCalculator calculator = new TaxCalculator();
            TaxSummary tax = calculator.GetDocumentTax(invoice);
            _taxtotal = tax.Taxes.GetTotalTax().Amount;
            _grandtotal = invoice.GetGrandtotal(tax).Amount;

            _accountingId = invoice.AccountingId;
            _transactionId = invoice.TransactionId;
            _transactionNumber = invoice.TransactionNumber;
        }

        public InvoiceDetailedSummary(InvoiceHeader invoice)
            : base(invoice)
        {
            _billTo = invoice.BillTo.GetContactInformation();
            _project = invoice.Project.GetProjectInfo();
            _project.ClientId = invoice.Client.Id; // use client ID on the invoice
            _subtotal = invoice.Subtotal;
            _grandtotal = invoice.Grandtotal;

            _accountingId = invoice.AccountingId;
            _transactionId = invoice.TransactionId;
            _transactionNumber = invoice.TransactionNumber;
        }

        public ContactInfo BillTo
        {
            get { return _billTo; }
            set { _billTo = value; }
        }

        public ProjectInfo Project
        {
            get { return _project; }
            set { _project = value; }
        }

        public decimal Subtotal
        {
            get { return _subtotal; }
            set { _subtotal = value; }
        }

        public decimal Taxtotal
        {
            get { return _taxtotal; }
            set { _taxtotal = value; }
        }

        public decimal Grandtotal
        {
            get { return _grandtotal; }
            set { _grandtotal = value; }
        }


        public string AccountingId
        {
            get { return _accountingId; }
            set { _accountingId = value; }
        }

        public string TransactionId
        {
            get { return _transactionId; }
            set { _transactionId = value; }
        }

        public int? TransactionNumber
        {
            get { return _transactionNumber; }
            set { _transactionNumber = value; }
        }
    }
}

完成堆栈跟踪:

    System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
 at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
 at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
 at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
 at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
 at Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
 at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, JsonSerializerSettings settings)
 at Pimarcnet.UserControls.Invoicing.ReceiptForm.get_ViewModel() in c:\PRL\DEV\Visual Studio 2012\Pimarcnet35\Pimarcnet35\UserControls\Invoicing\ReceiptForm.ascx.cs:line 42
 at ASP.usercontrols_invoicing_receiptform_ascx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\PRL\DEV\Visual Studio 2012\Pimarcnet35\Pimarcnet35\UserControls\Invoicing\ReceiptForm.ascx:line 164
 at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.Control.Render(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.Control.Render(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer)
 at System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output)
 at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.Control.Render(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
 at System.Web.UI.Page.Render(HtmlTextWriter writer)
 at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
 at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
 at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
 --- End of inner exception stack trace ---
 at System.Web.UI.Page.HandleError(Exception e)
 at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
 at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
 at System.Web.UI.Page.ProcessRequest()
 at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)
 at System.Web.UI.Page.ProcessRequest(HttpContext context)
 at ASP.pages_invoicing_editreceipt2_aspx.ProcessRequest(HttpContext context) in c:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\07d8779e\a6e74bf1\App_Web_hhnohwoa.4.cs:line 0
 at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
 at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

1 个答案:

答案 0 :(得分:1)

所有,我找到了造成这种异常的罪魁祸首,而且这并不容易。张贴让其他人受益。

在Receipt类中,PaymentMethod属性(特别是类型)导致序列化程序爆炸。当收据对象被水合时(来自数据库实体),引用的PaymentMethod属性实际上指向一个懒惰加载的数据库实体(即引用一个hibernate代理)。当序列化器序列化对象图时,hibernate正在注入导致错误的真实实体,至少这就是我的想法。

它仍然没有解释以下内容(我没有时间进一步调查,因为我需要完成项目):

1)在我的其他环境中,这不是问题。

2)至于踢,我(以非懒惰的方式)加载了一个PaymentMethod对象列表并尝试序列化...这再次触发了异常。 PaymentMethod类具有很少的简单属性,并且它不会引用任何其他可能延迟加载的实体。有趣的是,我尝试加载一个帐户列表(另一种类型,大部分都是相同的字段)并序列化。这有效!真奇怪。

故事的寓意:

如果你看到&#34;收藏被修改;枚举操作可能无法执行&#34;,查看您的对象图,看看您是否正在引用可能会延迟加载的对象。如果您仍然无法解决问题,请简化对象图,即。而不是嵌套复杂对象,从嵌套到根对象的字段中提取字段并序列化根。这正是我发现问题的方式。