Tôi có dịch vụ WCF C# bằng cách sử dụng điểm cuối webHttpBinding sẽ nhận và trả về dữ liệu ở định dạng JSON. Dữ liệu để gửi/nhận cần phải sử dụng một loại đa hình để dữ liệu của các loại khác nhau có thể được trao đổi trong cùng một "gói dữ liệu". Tôi có mô hình dữ liệu sau:Bảo quản các loại đa hình trong Dịch vụ WCF bằng cách sử dụng JSON
[DataContract]
public class DataPacket
{
[DataMember]
public List<DataEvent> DataEvents { get; set; }
}
[DataContract]
[KnownType(typeof(IntEvent))]
[KnownType(typeof(BoolEvent))]
public class DataEvent
{
[DataMember]
public ulong Id { get; set; }
[DataMember]
public DateTime Timestamp { get; set; }
public override string ToString()
{
return string.Format("DataEvent: {0}, {1}", Id, Timestamp);
}
}
[DataContract]
public class IntEvent : DataEvent
{
[DataMember]
public int Value { get; set; }
public override string ToString()
{
return string.Format("IntEvent: {0}, {1}, {2}", Id, Timestamp, Value);
}
}
[DataContract]
public class BoolEvent : DataEvent
{
[DataMember]
public bool Value { get; set; }
public override string ToString()
{
return string.Format("BoolEvent: {0}, {1}, {2}", Id, Timestamp, Value);
}
}
dịch vụ của tôi sẽ gửi/nhận các sự kiện sub-type (IntEvent, BoolEvent vv) trong một gói dữ liệu duy nhất, như sau:
[ServiceContract]
public interface IDataService
{
[OperationContract]
[WebGet(UriTemplate = "GetExampleDataEvents")]
DataPacket GetExampleDataEvents();
[OperationContract]
[WebInvoke(UriTemplate = "SubmitDataEvents", RequestFormat = WebMessageFormat.Json)]
void SubmitDataEvents(DataPacket dataPacket);
}
public class DataService : IDataService
{
public DataPacket GetExampleDataEvents()
{
return new DataPacket {
DataEvents = new List<DataEvent>
{
new IntEvent { Id = 12345, Timestamp = DateTime.Now, Value = 5 },
new BoolEvent { Id = 45678, Timestamp = DateTime.Now, Value = true }
}
};
}
public void SubmitDataEvents(DataPacket dataPacket)
{
int i = dataPacket.DataEvents.Count; //dataPacket contains 2 events, but both are type DataEvent instead of IntEvent and BoolEvent
IntEvent intEvent = dataPacket.DataEvents[0] as IntEvent;
Console.WriteLine(intEvent.Value); //null pointer as intEvent is null since the cast failed
}
}
Khi tôi gửi gói của tôi đến phương thức SubmitDataEvents
, mặc dù tôi nhận được các loại DataEvent
và cố gắng truyền chúng trở lại loại cơ sở của chúng (chỉ cho mục đích thử nghiệm) dẫn đến một số InvalidCastException
. Gói của tôi là:
POST http://localhost:4965/DataService.svc/SubmitDataEvents HTTP/1.1
User-Agent: Fiddler
Host: localhost:4965
Content-Type: text/json
Content-Length: 340
{
"DataEvents": [{
"__type": "IntEvent:#WcfTest.Data",
"Id": 12345,
"Timestamp": "\/Date(1324905383689+0000)\/",
"Value": 5
}, {
"__type": "BoolEvent:#WcfTest.Data",
"Id": 45678,
"Timestamp": "\/Date(1324905383689+0000)\/",
"Value": true
}]
}
Xin lỗi vì bài đăng dài, nhưng tôi có thể làm gì để bảo vệ các loại cơ sở của từng đối tượng không? Tôi nghĩ việc thêm gợi ý kiểu vào JSON và thuộc tính KnownType là DataEvent
sẽ cho phép tôi bảo tồn các loại - nhưng nó dường như không hoạt động.
Sửa: Nếu tôi gửi yêu cầu đến SubmitDataEvents
ở định dạng XML (với Content-Type: text/xml
thay vì text/json
) thì List<DataEvent> DataEvents
có chứa các tiểu loại thay cho loại siêu. Ngay sau khi tôi đặt yêu cầu thành text/json
và gửi gói ở trên thì tôi chỉ nhận được siêu loại và tôi không thể chuyển chúng sang loại phụ. yêu cầu cơ XML của tôi là:
<ArrayOfDataEvent xmlns="http://schemas.datacontract.org/2004/07/WcfTest.Data">
<DataEvent i:type="IntEvent" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Id>12345</Id>
<Timestamp>1999-05-31T11:20:00</Timestamp>
<Value>5</Value>
</DataEvent>
<DataEvent i:type="BoolEvent" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Id>56789</Id>
<Timestamp>1999-05-31T11:20:00</Timestamp>
<Value>true</Value>
</DataEvent>
</ArrayOfDataEvent>
Chỉnh sửa 2: Cập nhật mô tả dịch vụ sau bình luận của Pavel dưới đây. Điều này vẫn không hoạt động khi gửi gói JSON trong Fiddler2. Tôi chỉ nhận được một số List
có chứa DataEvent
thay vì IntEvent
và BoolEvent
.
Chỉnh sửa 3: Như Pavel đã đề xuất, đây là kết quả từ System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage.ToString()
. Có vẻ ổn với tôi.
<root type="object">
<DataEvents type="array">
<item type="object">
<__type type="string">IntEvent:#WcfTest.Data</__type>
<Id type="number">12345</Id>
<Timestamp type="string">/Date(1324905383689+0000)/</Timestamp>
<Value type="number">5</Value>
</item>
<item type="object">
<__type type="string">BoolEvent:#WcfTest.Data</__type>
<Id type="number">45678</Id>
<Timestamp type="string">/Date(1324905383689+0000)/</Timestamp>
<Value type="boolean">true</Value>
</item>
</DataEvents>
</root>
Khi truy tìm các deserialization của gói, tôi nhận được thông điệp sau đây trong các dấu vết:
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Verbose">
<TraceIdentifier>http://msdn.microsoft.com/en-GB/library/System.Runtime.Serialization.ElementIgnored.aspx</TraceIdentifier>
<Description>An unrecognized element was encountered in the XML during deserialization which was ignored.</Description>
<AppDomain>1c7ccc3b-4-129695001952729398</AppDomain>
<ExtendedData xmlns="http://schemas.microsoft.com/2006/08/ServiceModel/StringTraceRecord">
<Element>:__type</Element>
</ExtendedData>
</TraceRecord>
Thông báo này được lặp lại 4 lần (hai lần với __type
như phần tử và hai lần với Value
). Có vẻ như thông tin loại gợi ý đang bị bỏ qua thì các phần tử Value
bị bỏ qua vì gói được deserialized thành DataEvent
thay vì IntEvent
/BoolEvent
.
Wow ... Rất vui khi biết sự cố của bạn đã được giải quyết.Tuy nhiên, JSON được định dạng hoạt động tốt cho tôi, tôi luôn sao chép nó vào Fiddler và không có vấn đề gì. Tôi tin rằng nếu bạn chưa cài đặt tất cả các bản cập nhật cho khung công tác .NET hoặc phiên bản mới nhất có một lỗi lạ liên quan đến việc xử lý ký tự khoảng trắng. Tôi hoàn toàn bối rối. –
Đừng xấu hổ chút nào, tôi chưa bao giờ thấy rằng nếu không có sự giúp đỡ của bạn. Cách duy nhất tôi phát hiện ra là bằng cách gỡ lỗi mã nguồn WCF mà bạn đã đăng ở trên. Tôi nhận thấy rằng giá trị cho 'offset' luôn luôn quá thấp và xảy ra để nhận thấy rằng việc bao gồm các ký tự' \ r' và '\ n' trong bộ đệm tin nhắn đã loại bỏ tính toán bù trừ bằng cách nào đó. Tôi có thể đăng một câu hỏi khác để xem liệu có ai biết tại sao khoảng trắng cản trở việc phân tích cú pháp, vì tôi muốn tính linh hoạt của nó được bao gồm hay không. –
Ồ, điều đó đáng lẽ phải là 'bối rối' thay vì 'xấu hổ' :). Nhân tiện, tôi đã tìm thấy mô tả về một vấn đề tương tự [trong bài viết này] (http://blog.js-development.com/2010/05/n-will-break-your-json-jquery-wcf.html). –