How to fix XML serialization issues in ASMX web service - c#

We have an asmx web service A which is consuming a WCF service B with below DataContract structure.
[DataContract]
public class Animal
{
[DataMember]
string AnimalName { get; set; }
[DataMember]
Head[] head { get; set; }
}
[DataContract]
public class Person
{
[DataMember]
string PersonName { get; set; }
[DataMember]
Head[] head { get; set; }
}
[DataContract]
public class Head
{
[DataMember]
string Title { get; set; }
}
We are receiving below error while running an asmx web service A.
Types 'Animal.Head' and 'Person.Head' both use the XML type name, 'Head', from namespace 'http://tempuri.org/'. Use XML attributes to specify a unique XML name and/or namespace for the type.
We also tried putting a different XMLElement namespace in DataContract but didn't help.
[XmlElement(Namespace = "urn:/A/Animal/")]
[DataMember]
Head[] head { get; set; }
Any help on this is much appreciated.

XmlElement is used for XmlSerializer, wcf by default uses DataContractSerializer to
serialize and deserialize model.
If you want to use XmlSerializer , you could refer to
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-the-xmlserializer-class
DataContract also has a Namespace property which could specify namespace for your model.

Related

DataContract Serializer and Json.Net When using object that contains property of type XmlElement

We currently have an object what we are using to pass around information about incoming API calls of of the properties is the message itself. The message property is an XmlElement and the DataContract serializer is happy to do it's thing with an XmlElement.
We are no adding on to our API and these web services are making RPC via SignalR to hosted clients across the united states. What I have found is that the Json.Net library is not happy with an XmlElement I get the following message "Xmlnodeconverter only supports deserializing xml document". Okay fine so I'll use an XmlDocument then and get around this problem... But wait the DataContract Serailizer isn't happy with an XmlDocument. It seems to be a situation where I cant have my cake and eat it too. If I go with XmlDocument the SignalR client is happy but the rest of the applications are not, and if I use a XmlElement the SignlR client can't recive the message.
Note: the SignalR client is a self hosted windows service not javascript.
So what I want to know is. Is there a way to either get Json.net to except XmlElement or the DataContract Serializer to except XmlDocument. It would be much simpler for us to change the SignalR side of things as this is new and the rest of the applications alrady understand the XmlElement.
Here is the object that contains the XmlElement:
[DataContract(Name = "AuditData")]
public class AuditData
{
[DataMember]
public XmlElement Message { get; set; }
[DataMember]
public XmlDocument MessageV2 { get; set; }
[DataMember]
public IList<ErrorMessage> Errors { get; set; }
[DataMember]
public string DealerCode { get; set; }
[DataMember]
public DateTime Time { get; set; }
[DataMember]
public IntegrationTransactionTypeEnum TransationType { get; set; }
[DataMember]
public string BooksAccountNumber { get; set; }
[DataMember]
public IntegrationStepIdEnum Step { get; set; }
[DataMember]
public IntegrationErrorLevelEnum? ErrorLevel { get; set; }
[DataMember]
public IEnumerable<Criteria> Search { get; set; }
}

Using Datacontract: WCF

How should i be declaring the datacontracts
My Operation contract has a Method:
Apple GetApples()
My data Contract Apple looks Like
[DataContract]
public class Apple
{
[DataMember]
public int Id { get; set; }
[DataMember]
public FruitType type { get; set; }
}
As there is another member of type FruitType.
[DataContract]
public class FruitType
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string type { get; set; }
}
OR
as a simple class
public class FruitType
{
public int Id { get; set; }
public string type { get; set; }
}
What is the difference between these two? other than that the simple type is not a datacontract and will depende on how i want to use it.?
how should i declare it??
Those attributes give you the control over how your properties will be represented in different formats. For example for XML you can specify the XML Namespace and XML node names.
Even if you are happy with default property names and default namespace, when you try to serialize data to XML, your XML nodes will have weird names such as typek_BackingField.
In other words, if you use WCF you should use DataContract and DataMember attributes, even if you think it works fine the formatted data may not look what you expect. As a result it removes compatibility with other (non-WCF) systems. Or even when you don't share your types (contracts) with other WCF systems.

Serializing a List of Interfaces using the DataContractSerializer

I have a class and there are some nested classes within it. I serialize it and send it to the wcf service using a method with no problems. Here's the class;
public class ComputerDTO
{
[DataMember]
public ComputerTypeDTO Type { get; set; }
[DataMember]
public string ComputerName { get; set; }
[DataMember]
public MonitorDTO Monitor { get; set; }
}
Here's the method;
public void Check()
{
Computer c = new Computer();
ISystemInfoOperations cli = GetServiceClient();
Mapper.CreateMap<Monitor, MonitorDTO>();
Mapper.CreateMap<IHardwarePart, IHardwarePartDTO>();
Mapper.CreateMap<Computer, ComputerDTO>()
.ForMember(s => s.Hardware, m => m.MapFrom(q => Mapper.Map<List<IHardwarePart>, List<IHardwarePartDTO>>(q.Hardware)));
Mapper.AssertConfigurationIsValid();
ComputerDTO dto = Mapper.Map<Computer, ComputerDTO>(c);
string sendComputerInfo = cli.SendComputerInfo(dto);
}
But I have also a list of interface to be sent. So I change the code like below and get an error.
public class ComputerDTO
{
[DataMember]
public ComputerTypeDTO Type { get; set; }
[DataMember]
public string ComputerName { get; set; }
[DataMember]
public MonitorDTO Monitor { get; set; }
[DataMember]
public List<IHardwarePartDTO> Hardware { get; set; }
}
public interface IHardwarePartDTO
{
[DataMember]
string Name { get; set; }
[DataMember]
HardwarePartTypeDTO PartType { get; set; }
}
Inside of hardware is getting filled in the project. But if I try to send it, I get this famous error :
Type
'Proxy'
with data contract name
'_x0030__Culture_x003D_neutral_PublicKeyToken_x003D_null_x003E_:http://schemas.datacontract.org/2004/07/Proxy%3CSystemInfo.DTO.IHardwarePartDTO_SystemInfo.DTO_Version=1.0.0'
is not expected. Consider using a DataContractResolver or add any
types not known statically to the list of known types - for example,
by using the KnownTypeAttribute attribute or by adding them to the
list of known types passed to DataContractSerializer.
The DataContractSerializer needs to know about the concrete types that is might return. An interface cannot be serialized, as it cannot be deserialized (how can you create an instance of an interface without a concrete implementation).
The simple resolution is to add KnownTypes attribute like below:
[KnownType(typeof(your hardware dto concrete type here))]
public class ComputerDTO
{
[DataMember]
public ComputerTypeDTO Type { get; set; }
[DataMember]
public string ComputerName { get; set; }
[DataMember]
public MonitorDTO Monitor { get; set; }
[DataMember]
public List<IHardwarePartDTO> Hardware { get; set; }
}
You can add as many known type attributes as you like.
Slightly more complex is the ServiceKnownTypes attribute. This is very similar but you would add it to your service class.
Other than that you can use a data contract resolver - but this is very complicated and would take a while to explain.
EDIT: 18/02/2013 15:11
You may also need to look at you Automapper as its currently going to create proxies in your Hardware list - and proxies cannot be serialized. You need to tell automapper what to serialize them to - for example:
Mapper.CreateMap<Monitor, MonitorDTO>();
Mapper.CreateMap<Monitor, IHardwarePartDTO>().As<MonitorDTO>();
Mapper.CreateMap<Audio, AudioDTO>();
Mapper.CreateMap<Audio, IHardwarePartDTO>().As<AudioDTO>();
Mapper.CreateMap<CDROMDrive, CDROMDriveDTO>();
Mapper.CreateMap<CDROMDrive, IHardwarePartDTO>().As<CDROMDriveDTO>();
//you need entries like these for everythin that implements IHardwarePartDTO
This way automapper knows what it needs to create.

WCF was unable to deserialize List with in a Dictionary element

[DataContract]
public class AssetData
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<AssetData> ChildAssets { get; set; }
[DataMember]
public int Priority { get; set; }
[DataMember]
public AssetData ParentNode { get; set; }
}
[ServiceKnownType(typeof(Dictionary<string, AssetData>))]
public interface IRtxEquipmentConfiguration
{
[OperationContract]
object GetData(string sKey, string sRequest);
}
For the above OperationContract "GetData" the server is returning a Dictionary of AssetData.
I have marked AssetData as a DataContract and all its fields as DataMembers.
At the client side, I was getting wcf error "The socket connection has been disposed.\r\nObject name: 'System.ServiceModel.Channels.SocketConnection'.". I suspected this error is because of the field ChildAssets.
When I disable this field alone (By removing DataMember tag), then at the client side, I was able to get all the Dictionary elements and with in each element all the fields except ChildAssets.
I am able to see remaining fields Name, ParentNode and Priority.
Any clue why WCF fails to serialize a List with in a Dictionary element?
I have fixed the issue by adding IsReference = true to my DataContract class AssetData. The object graph has references to other instances of AssetData class. ChildAssets members are just references to other instances of AssetData.

Hide public Property when exposed through web service

I would like to prevent a property from being exposed via my WCF web service. I tried adding the XmlIgnore attribute bug that didn't work. We are using .NET 3.5. WCF.
This doesn't work:
public class MyClass
{
public string S1 { get; set; }
[XmlIgnore]
public string S2NotExposed { get; set; }
}
Mark your class with the [DataContract] attribute from the DataContractAttribute Class , then mark only the properties you want to expose with the [DataMember] attribute from the DataMemberAttribute Class.

Categories