A WCF Data Contract describes the structure or type of data being exchanged between the client and server. In some scenarios the type of data is not known between the client and server. For example the data the service is sending back to the client is not the actual data of the contract but a derived type of it. Then how can we expect the DataContractserializer to determine this relationship? Until we say this relationship to the DataContractSerializer, this deserialization issue will not be resolved. Is my explanation still not good enough to explain the problem? Let me explain it with the following source code.
- public interface IOnlineShoppingService
- {
- [OperationContract(Name = "StockAvailability")]
- bool IsStockAvailable(string sModelNumber);
-
- [OperationContract(Name = "CalculatePrice", ProtectionLevel = System.Net.Security.ProtectionLevel.None)]
- double CalculatePrice(string sModelNumber, int iQuantity, string sDeliveryLocation,int iDiscountCouponNum);
-
- [OperationContract(Name = "GetWholeSaleDealerInfo")]
- WholeSaleDealersInfo GetwholeSaleDealerInfo(string sFilterByCity);
- }
- [DataContract]
- public class WholeSaleDealersInfoDetailed:WholeSaleDealersInfo
- {
-
- }
- public WholeSaleDealersInfo GetwholeSaleDealerInfo(string sFilterByCity)
{
- switch (sFilterByCity)
- {
- case "Chennai":
- if (sFilterByCity.Equals("Chennai"))
- {
- WholeSaleDealersInfoDetailed wsDealerDetailed = new WholeSaleDealersInfoDetailed();
- wsDealerDetailed.DealerName = "Rameshkartik";
- wsDealerDetailed.DealerLocation = "Chennai";
- wsDealerDetailed.DealerSince = DateTime.Now;
- wsDealerDetailed.DealerEmail = "[email protected]";
- wsDealerDetailed.DealerAddress = "North Street,Chennai";
- return wsDealerDetailed;
- }
- break;
- return null;
- }
- return null;
- }
In the preceding service interface you can find a method called GetWholeSaleDealerInfo that returns the type WholeSaleDealersInfo, but the DataContractSerializer will expect only the type WholeSaleDealersInfo, not the WholeSaleDealersInfoDetailed. This is the problem, during the deserialization the actual contract will not be coming, but it is a derived one. So what is the solution for this? As discussed earlier, Known Types in a Data Contract is the right way to solve this. You can use Known Types at the various levels based on your needs.
- Global Level
- Service Contract Level
- Operation Contract Level
Global Level
- [KnownType(typeof(WholeSaleDealersInfoDetailed))]
- [DataContract]
- public class WholeSaleDealersInfo
- {
- }
In the preceding example, you can see that the KnownType attribute is used at the Data Contract level. It means that the type is globally known to all the service contracts and operation contracts wherever the WholeSaleDealersInfo type is used.
Service Contract Level
- [ServiceKnownType(typeof(WholeSaleDealersInfoDetailed))]
- public interface IOnlineShoppingService
- {
- [OperationContract(Name = "GetWholeSaleDealerInfo")]
- WholeSaleDealersInfo GetwholeSaleDealerInfo(string sFilterByCity);
- }
If you want to use this derived type as a known type for a specific service, please use the preceding syntax Service Known Type.
Operation Contract Level
- public interface IOnlineShoppingService
- {
- [ServiceKnownType(typeof(WholeSaleDealersInfoDetailed))]
- [OperationContract(Name = "GetWholeSaleDealerInfo")]
- WholeSaleDealersInfo GetwholeSaleDealerInfo(string sFilterByCity);
- }
If you want tp use the derived type as known for a specific method, please place the serviceknown type attribute on the service method as above.
We can do the same in the web.config as well.
Attachment
Refer to the code attachment for further details.
Summary
Known Types can be used at various levels, there are Global Level, Service Contract Level and Data Contract Level.