2013-08-09 30 views
6

Tôi đang đối mặt với một vấn đề rất khó chịu mà tôi không thể xác định.
Tôi đang chạy một ứng dụng ASP.Net rất lớn có chứa hàng nghìn đối tượng; Nó sử dụng serialization/deserialization trong bộ nhớ với MemoryStream để sao chép trạng thái của ứng dụng (hợp đồng bảo hiểm) và chuyển nó vào các module khác. Nó hoạt động tốt trong nhiều năm. Bây giờ thỉnh thoảng, không có hệ thống, trong serialization nó ném ngoại lệPhương thức khởi tạo mảng byte thập phân trong Binaryformatter Serialization

Decimal constructor mảng byte yêu cầu một mảng có độ dài Bốn chứa byte thập phân hợp lệ.

Chạy cùng một ứng dụng với cùng một dữ liệu, 3 lần trong số 5 hoạt động. Tôi đã bật tất cả ngoại lệ CLR, Gỡ lỗi - Ngoại lệ - CLR ngoại lệ - Đã bật, vì vậy tôi đoán rằng nếu khởi tạo sai/gán cho trường thập phân xảy ra, chương trình sẽ dừng lại. Nó không xảy ra.
Tôi đã cố gắng phân chia tuần tự hóa trong nhiều đối tượng tiểu học hơn nhưng rất khó, để xác định trường gây ra sự cố. Từ phiên bản đang hoạt động trong sản xuất và phiên bản này tôi đã chuyển từ .Net 3.5 sang .NET 4.0 và những thay đổi nhất quán đối với phần giao diện người dùng, không phải là phần kinh doanh, đã được thực hiện. Kiên nhẫn tôi sẽ trải qua tất cả các thay đổi.

Dường như vấn đề C lỗi thời cũ khi char *p đang viết ở nơi không nên, và chỉ trong quá trình tuần tự hóa khi kiểm tra tất cả các vấn đề dữ liệu xuất hiện.

Có điều gì đó giống như điều này trong môi trường được quản lý của .Net không? Ứng dụng này rất lớn nhưng tôi không thể thấy sự tăng trưởng bộ nhớ bất thường. Điều gì có thể là một cách để gỡ lỗi và theo dõi sự cố?

Dưới đây là một phần của stacktrace

[ArgumentException: Decimal byte array constructor requires an array of length four containing valid decimal bytes.] 
    System.Decimal.OnSerializing(StreamingContext ctx) +260 

[SerializationException: Value was either too large or too small for a Decimal.] 
    System.Decimal.OnSerializing(StreamingContext ctx) +6108865 
    System.Runtime.Serialization.SerializationEvents.InvokeOnSerializing(Object obj, StreamingContext context) +341 
    System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +448 
    System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo) +969 
    System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) +1016 
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) +319 
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) +17 
    Allianz.Framework.Helpers.BinaryUtilities.SerializeCompressObject(Object obj) in D:\SVN\SUV\branches\SUVKendo\DotNet\Framework\Allianz.Framework.Helpers\BinaryUtilities.cs:98 
    Allianz.Framework.Session.State.BusinessLayer.BLState.SaveNewState(State state) in 

Xin lỗi vì những câu chuyện dài và câu hỏi không xác định, tôi thực sự sẽ đánh giá cao sự giúp đỡ nào.

+0

Tôi gặp lỗi tương tự, hóa ra là do liên kết (sử dụng StructLayout (LayoutKind.Explicit)) w ở đây tôi đã giải thích một bool như một số thập phân vô tình. Phần còn lại của ứng dụng sử dụng số thập phân như bình thường 0, nhưng chỉ trong quá trình deserialization trong một ứng dụng riêng biệt nó sẽ ném lỗi này, tôi nhận ra vấn đề bằng cách làm Decimal.GetBytes trước khi serialization và chú ý thứ 3 đến byte cuối cùng là 1 thay vì 0 như mong đợi. – BrandonAGr

Trả lời

3

Đó là .... rất thú vị; đó không thực sự là đọc hoặc ghi dữ liệu vào thời điểm đó - nó đang gọi cuộc gọi lại tuần tự hóa trước, hay còn gọi là [OnSerializing], mà ở đây ánh xạ tới decimal.OnSerializing. Những gì rằng không cố gắng kiểm tra các bit - nhưng có vẻ như chỉ đơn giản là một lỗi trong BCL. Dưới đây là việc thực hiện trong 4,5 (ho "phản xạ" ho):

[OnSerializing] 
private void OnSerializing(StreamingContext ctx) 
{ 
    try 
    { 
     this.SetBits(GetBits(this)); 
    } 
    catch (ArgumentException exception) 
    { 
     throw new SerializationException(Environment.GetResourceString("Overflow_Decimal"), exception); 
    } 
} 

Các GetBits nhận được/mid/hi/cờ mảng lo, vì vậy chúng ta có thể khá chắc chắn rằng mảng truyền cho SetBits là phi vô chiều dài phù hợp. Vì vậy, cho rằng thất bại, phần mà phải thất bại là ở SetBits, ở đây:

int num = bits[3]; 
    if (((num & 2130771967) == 0) && ((num & 16711680) <= 1835008)) 
    { 
     this.lo = bits[0]; 
     this.mid = bits[1]; 
     this.hi = bits[2]; 
     this.flags = num; 
     return; 
    } 

Về cơ bản, nếu if kiểm tra đi chúng tôi có được trong, gán các giá trị, và thoát thành công; nếu thử nghiệm ifkhông thành công, nó sẽ kết thúc bằng việc ném ngoại lệ. bits[3] là đoạn flags, giữ dấu và tỷ lệ, IIRC. Vì vậy, câu hỏi ở đây là: làm thế nào bạn có được giữ một không hợp lệ decimal với một đoạn flags bị hỏng?

Lưu ý ở đây: 2130771967 là mặt nạ:

0111 1111 0000 0000 1111 1111 1111 1111 

16711680 là mặt nạ:

0000 0000 1111 1111 0000 0000 0000 0000 

và 1.835.008 là mặt nạ

0000 0000 0001 1100 0000 0000 0000 0000 

(đó là số thập phân 28 trong upper word)

để báo giá từ MSDN:

Phần tử thứ tư của mảng được trả về chứa hệ số tỷ lệ và dấu hiệu . Nó bao gồm các phần sau: Các bit 0 đến 15, từ thấp hơn, không được sử dụng và phải bằng không. Các bit từ 16 đến 23 phải chứa số mũ trong khoảng từ 0 đến 28, cho biết sức mạnh của 10 để chia cho số số nguyên. Các bit 24 đến 30 không được sử dụng và phải bằng không. Bit 31 chứa dấu: 0 có nghĩa là dương và 1 có nghĩa là âm.

Vì vậy, để không thử nghiệm này:

  • số mũ là không hợp lệ (bên ngoài 0-28)
  • từ thấp không phải là zero
  • byte trên (trừ MSB) là không khác

Thật không may, tôi không có cách nào để tìm kiếm decimal nào không hợp lệ ...

.210

Cách duy nhất tôi có thể nghĩ đến tìm kiếm ở đây là:

  • phân tán GetBits/new decimal(bits) khắp mã của bạn - có lẽ như một phương pháp void SanityCheck(this decimal) (có thể với một [Conditional("DEBUG")] hoặc một cái gì đó)
  • thêm [OnSerializing] phương pháp vào chính của bạn mô hình miền, nhật ký đó ở đâu đó (bàn điều khiển có thể) để bạn có thể xem đối tượng nào đang hoạt động khi nó phát nổ
+0

Thông báo ngoại lệ có vẻ khá gây hiểu nhầm - nó nói về một mảng gồm 4 "byte thập phân" và không có hàm tạo nào cho 'thập phân' ... Và dù sao thì" byte thập phân "là gì? –

+0

@MatthewWatson thực sự - chúng tôi thậm chí không sử dụng hàm tạo tại đây; thông thường, 'SetBits' được gọi bởi' thập phân công khai (int [] bits) ', mà kinda giải thích thông điệp đó, nhưng có: gây nhầm lẫn. –

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