46

Tôi đang sắp xếp lại chuỗi tuần tự XML của mình và tôi đã tìm ra DataContractSerializer. Tất cả mọi thứ chạy rất tốt, cho đến khi nó cần phải serialize lớp này:"Loại không mong đợi", sử dụng DataContractSerializer - nhưng nó chỉ là một lớp đơn giản, không có công cụ vui nhộn?

using System; 
using System.Runtime.Serialization; 

namespace VDB_Sync.Model 
{ 
[DataContract(Name="Konstant")] 
public class Konstant : DataFelt 
{ 
    [DataMember] 
    private MySqlDbType mydataType; 
    [DataMember] 
    private object value; 

    public Konstant(string navn, MySqlDbType dataType, object value) 
     : base(navn, dataType, "*Konstant", false, false) 
    { 
     //this.navn = navn; 
     this.mydataType = dataType; 
     this.value = value; 

     if (navn.Contains("*Løbenummer")) 
     { 
      navn = "*Konstant: " + Convert.ToString(value); 
     } 
    } 

    public object Value 
    { 
     get 
     { 
      return value; 
     } 
    } 

} 
} 

Nó cung cấp cho của tôi đây:

Loại 'VDB_Sync.Model.Konstant' bằng tên hợp đồng dữ liệu 'Konstant: http://schemas.datacontract.org/2004/07/VDB_Sync.Model 'không được mong đợi. Hãy xem xét sử dụng một DataContractResolver hoặc thêm bất kỳ loại không được biết đến tĩnh danh sách các loại đã biết - ví dụ, bằng cách sử dụng thuộc tính KnownTypeAttribute hoặc bằng cách thêm chúng vào danh sách các loại đã biết được truyền cho DataContractSerializer.

* Trợ giúp tôi đã tìm thấy cho đến nay chỉ đến các bộ sưu tập và loại. Tôi có một enum (MySqlDbType) trong lớp của tôi - nhưng có được điều này: Tôi thậm chí có được cùng một lỗi khi tôi không có DataMembers tuyên bố ở tất cả: -x Vì vậy, những gì đang xảy ra ở đây? Tôi đang thiếu gì?

để tham khảo, đây là làm thế nào tôi đăng nó, VDB_SessionController là root: *

public void GemKonfig(VDB_SessionController session) 
    { 
     var settings = new XmlWriterSettings() 
     { 
      Indent = true, 
      IndentChars = "\t" 
     }; 

     var writer = XmlWriter.Create(defaultFile, settings); 
     DataContractSerializer ser = 
      new DataContractSerializer(typeof(VDB_SessionController)); 

     ser.WriteObject(writer, session); 
     writer.Close(); 
    } 

Trả lời

50

Trường hợp ngoại lệ mà đã được báo cáo là dành cho VDB_Sync.Model.Konstant. Điều này có nghĩa rằng một nơi nào đó tiếp tục lên chuỗi, lớp này đang được kéo vào một lớp khác và lớp đó là lớp đang được đăng.

Vấn đề là tùy thuộc vào cách Konstant được nhúng trong lớp này (ví dụ, nếu nó nằm trong một bộ sưu tập hoặc danh sách chung), DataContractSerializer có thể không được chuẩn bị cho sự xuất hiện của nó trong quá trình deserialization.

Để giải quyết vấn đề này, bạn cần áp dụng thuộc tính kiểu đã biết cho lớp có chứa Konstant. Dựa trên mã tuần tự hóa của bạn, tôi nghi ngờ rằng đây là VDB_SessionController.

Vì vậy, hãy thử trang trí lớp học này với thuộc tính KnownType:

[KnownType(typeof(VDB_Sync.Model.Konstant)] 
public class VDB_SessionController 
+0

Tuyệt vời - nó hoạt động! Dường như tôi cần phải làm điều này với rất nhiều lớp học, cảm ơn! – Julian

+2

Làm cách nào để thêm trang trí này nếu lớp được tạo bởi khung thực thể? –

+0

Tuyệt vời! Bây giờ tôi cũng hiểu mục đích của trang trí "KnownType"! Cảm ơn! – Homer1982

0

Thay đổi này:

[DataContract(Name="Konstant")] 
public class Konstant : DataFelt 

này:

[DataContract(Name="Konstant")] 
[KnownTypes(typeof(somenamespace.DataFelt))] 
public class Konstant : DataFelt 
+0

Đóng nhưng không có con xúc xắc:/ – Julian

+0

Các KnownTypeAttribute cần phải đi vào lớp cơ sở. – Bryan

+0

Nếu bạn không có quyền truy cập vào loại cơ sở thì sao? – Choco

8

Bạn cũng có thể kết hợp [KnownType] và phản ánh để làm cho mã của bạn chịu hơn với những thay đổi trong tương lai.

[DataContract] 
[KnownType("GetKnownPersonTypes")] 
internal class Person 
{ 
    private static IEnumerable<Type> _personTypes; 

    private static IEnumerable<Type> GetKnownTypes() 
    { 
     if (_personTypes == null) 
      _personTypes = Assembly.GetExecutingAssembly() 
            .GetTypes() 
            .Where(t => typeof (Person).IsAssignableFrom(t)) 
            .ToList(); 
     return _personTypes; 
    } 
} 

Bây giờ một DataContractSerializer/DataContractJsonSerializer/XmlSerializer cấu hình để làm việc với Person, cũng sẽ làm việc với bất kỳ loại có nguồn gốc từ Person (miễn là nó được công bố trong cùng một assembly).

15

Thêm URL này vào WebApiConfig.cs

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

var json = config.Formatters.JsonFormatter; 

json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; 
config.Formatters.Remove(config.Formatters.XmlFormatter); 

tham khảo: http://www.datazx.cn/Forums/en-US/a5adf07b-e622-4a12-872d-40c753417645/action?threadDisplayName=web-api-error-the-objectcontent1-type-failed-to-serialize-the-response-body-for-content&forum=wcf

+8

Tất cả điều này làm vô hiệu hóa tuần tự hóa XML, đó là lý do tại sao ngoại lệ này biến mất. Tuy nhiên nếu bạn cần serialization XML câu trả lời này sẽ không giúp đỡ. Ngoài ra, bạn chỉ cần dòng cuối cùng: 'config.Formatters.Remove (config.Formatters.XmlFormatter);' Mọi thứ ở trên dòng đó là không liên quan. – niaher

2

Nó giống như là @Leon gợi ý nhưng với việc sửa chữa từ @Bryan, các 'KnownTypeAttribute' nên được trên lớp cơ sở, vì vậy nó phải như thế này:

[DataContract(Name="DataFelt")] 
[KnownType(typeof(somenamespace.Konstant))] 
public class DataFelt 

và trong subclass:

[DataContract(Name="Konstant")] 
public class Konstant : DataFelt 
3

vấn đề đối với tôi là tôi là r eturning giao diện (IIndividual) từ bộ điều khiển WebAPI của tôi. Khi tôi thay đổi kiểu trả về kiểu Class (Individual), lỗi này biến mất.

Không làm việc:

[HttpGet] 
    [Route("api/v1/Individual/Get/{id}")] 
    public IIndividual Get([FromUri]int id) 
    { 
     return _individualService.Get(id); 
    } 

làm việc:

[HttpGet] 
    [Route("api/v1/Individual/Get/{id}")] 
    public Individual Get([FromUri]int id) 
    { 
     IIndividual individual = _individualService.Get(id); 
     return individual as Individual; 
    }