I have WSDL service class in which I would like to add extra properties. When I am trying to deserialize my derived class its giving error "You need to add XmlChoiceIdentifierAttribute to the 'ObjCreatePaperClipTransaction' member."
Here is the code I wrote on top of service classes. (executeCreatePaperClipTransaction & CreatePaperClipTransactionType are classes from proxy object)
namespace MyProject.DTO
{
[XmlType("executeCreatePaperClipTransaction")]
public partial class CustomExecuteCreatePaperClipTransaction : executeCreatePaperClipTransaction
{
[XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
[XmlElement("CreatePaperClipTransaction")]
public CustomCreatePaperClipTransactionType ObjCreatePaperClipTransaction { get; set; }
}
public partial class CustomCreatePaperClipTransactionType : CreatePaperClipTransactionType
{
[XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public executeCreateLoanIncrease ObjLoanIncreaseRequest { get; set; }
[XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public executeCreateFreeFormEventFeePayment ObjFreeFormEventFeePaymentRequest { get; set; }
}
}
When I remove [XmlElement("CreatePaperClipTransaction")] line, its working fine. But in the seralized xml i want tag name to be CreatePaperClipTransaction and not ObjCreatePaperClipTransaction
I went through this answer but I am not sure how can i implement in my case https://stackoverflow.com/a/20379038/1169180
Rather than adding two separate [XmlElement] attributes to your ObjCreatePaperClipTransaction property, you should add one single attribute with all necessary information:
[XmlType("executeCreatePaperClipTransaction")]
public partial class CustomExecuteCreatePaperClipTransaction : executeCreatePaperClipTransaction
{
[XmlElement(ElementName = "CreatePaperClipTransaction", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public CustomCreatePaperClipTransactionType ObjCreatePaperClipTransaction { get; set; }
}
Working .Net fiddle.
When you add multiple [XmlElement] attributes to a property, you are informing XmlSerializer that multiple different XML element names should be bound to the same property, for instance because the property value is polymorphic:
public class BaseClass
{
}
public class DerivedClass : BaseClass
{
}
public class RootObject
{
[XmlElement(ElementName = "BaseClassProperty", Type = typeof(BaseClass))]
[XmlElement(ElementName = "DerivedClassProperty", Type = typeof(DerivedClass))]
public BaseClass Property { get; set; }
}
In the example above, if the Property is assigned a DerivedClass value, the following XML will be generated:
<RootObject>
<DerivedClassProperty />
</RootObject>
That doesn't seem to apply here. You just want to bind your property to the XML element name <CreatePaperClipTransaction>.
Related
The issue:
Entity object has it properties related to databases on its own, but the needs in the programming area is differ, sometimes we want to add it some more:
Properties – that is for temporary logic.
Methods – for clean code and for programming necessaries.
Finally yet importantly – Attribute for authorization, display, filters etc.
However, obviously we do not want our program to be maintainability without needs to rewrite code just after we update the model.
For properties and methods, the Entity Framework platform generated all the object from model as partial classes and the .NET environment allow us to extend them as we wish:
Remember to check that our partial sit in same namespaces (Notice that when we create them in model directory or in them own directory Visual Studio create addition namespace).
public partial class ErrorLog
{
public long pk { get; set; }
public int lineNumber { get; set; }
public Nullable<int> error { get; set; }
}
Our partial:
public partial class ErrorLog
{
public string getErrorDescription()
{
return d[(int)error];
}
private static Dictionary<int, string> d = new Dictionary<int, string>()
{
{1,"desc1" },
{2,"desc2" },
{3,"desc3" },
{4,"desc4" }
};
}
For attributes:
We can add new interface
public interface IErrorLogsMetaData
{
[Display(Name = "Id")]
long pk { get; set; }
[Display(Name = "The line Number")]
int lineNumber { get; set; }
[Display(Name = "The Error")]
Nullable<int> error { get; set; }
}
Implement them on our Entity (even extended) object.
For that we need to reflect and book it in global.asax by using:
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(typeof(ErrorLog), typeof(IErrorLogsMetaData)), typeof(ErrorLog));
TypeDescriptor – familiar for us from reflection, its get information about type.
AddProviderTransparent – is the method called from my partially trusted code and get metadata from associated class.
The first parameter is the provider and it TypeDescriptionProvider from the type we want to decorate and the attributed interface, the second parameter is the target type for decription.
Another Option
Make your partial view to implement the IErrorLogsMetaData and then you don't need to associate at Global.asax
As you can see, the database first entity model classes are partial, so you can create your own partial class, for example if you have:
public partial class SomeClass
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
You can do something like this:
Add some class to your project, name it SomeClassPartial:
//SomeClassPartial.cs
namespace YourNamespace
{
[MetadataType(typeof(SomeClassMetadata))]
public partial class SomeClass
{
//add your new properties/some_logic here
public string NewPropX { get; set; }
public string NewPropY { get; set; }
}
public partial class SomeClassMetadata
{
//metadata for your existing model properties
[Display(Name = "Property 1")]
public string Prop1 { get; set; }
[Display(Name = "Property 2")]
public string Prop2 { get; set; }
}
}
In your SomeClassMetadata class you can add data annotation attributes to your existing properties with MetadataType attribute, which will specify the metadata class to associate with a data model class, and with that you can tell you partial SomeClass class to get that attributes from SomeClassMetadata class. To add new custom properties, you can use SomeClass partial class.
MSDN Link: MetadataTypeAttribute Class
The data source I'm using always sends over data with the same parent class (Models in the xml), with xsi:type to determine the actual type of the class. This has been working fine until they started adding a namespace to the xsi:type. Now it won't deserialize no matter what I try.
Here's the XML:
<ModelResource xmlns:ot="http://www.example.com/otSpace">
<Models xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance xsi:type="ot:myChildClass">
Stuff here
</Models>
</ModelResource>
The root node
[XmlRoot("ModelResource")]
public class XmlRoot
{
[XmlElement("Models")]
public List<BaseObject> Bases { get; set; }
}
The parent class
[XmlInclude(typeof(MyChildClass))]
public abstract class BaseObject
{
}
The child class
[XmlType(TypeName = "myChildClass", Namespace = "http://www.example.com/otSpace")]
public class MyChildClass : BaseObject
{
}
When I deserialize this XML, I wind up with the error:
{"The specified type was not recognized: name='myChildClass', namespace='http://www.example.com/otSpace', at ."}
Thanks for your help.
These classes work with your example. I've named the classes the same as the element names just to make it easier to follow:
public class ModelResource
{
public Models Models { get; set; }
}
[XmlInclude(typeof(MyChildClass))]
[XmlRoot(Namespace = "")]
public abstract class Models
{
}
[XmlType("myChildClass", Namespace = "http://www.example.com/otSpace")]
public class MyChildClass : Models
{
[XmlText]
public string Value { get; set; }
}
See this fiddle for a working demo.
I need to sandwich an element inside of another element. Is it possible to serialize XML like this?
http://pastebin.com/7qDE7Ses
Here is my class
[XmlRoot(ElementName = "SalesOrderMod")]
public partial class SalesOrderMod
{
[XmlElementAttribute(Order = 1)]
public string TxnID { get; set; }
[XmlElementAttribute(Order = 2)]
public string EditSequence { get; set; }
[XmlElementAttribute(Order = 3)]
public string ShipDate { get; set; }
[XmlElementAttribute(Order = 4)]
public ListRef ShipMethodRef = new ListRef();
public bool ShouldSerializeShipMethodRef()
{
return !(String.IsNullOrEmpty(ShipMethodRef.FullName));
}
[XmlElementAttribute(Order = 5)]
public string Other { get; set; }
[XmlElementAttribute(Order = 6, ElementName = "SalesOrderLineMod")]
public List<LineMod> SalesOrderLineMod = new List<LineMod>();
[XmlElementAttribute(Order = 7, ElementName = "SalesOrderLineGroupMod")]
public List<LineMod> SalesOrderLineGroupMod = new List<LineMod>();
}
You originally indicated you would like to serialize a series of elements inside an XML document like so:
<SalesOrderLineRet>
</SalesOrderLineRet>
<SalesOrderLineGroupRet>
</SalesOrderLineGroupRet>
<SalesOrderLineRet>
</SalesOrderLineRet>
You can if the types that correspond to SalesOrderLineRet and SalesOrderLineGroupRet have some common base type T, and they are stored in a List<T>. For instance, the following class definitions:
public abstract class SalesOrderLineRetBase
{
}
public class SalesOrderLineRet : SalesOrderLineRetBase
{
}
public class SalesOrderLineGroupRet : SalesOrderLineRetBase
{
}
public class RootObject
{
[XmlElement(typeof(SalesOrderLineRetBase))]
[XmlElement(typeof(SalesOrderLineRet))]
[XmlElement(typeof(SalesOrderLineGroupRet))]
public List<SalesOrderLineRetBase> SalesOrders { get; set; }
}
Will, when serialized, produce the following XML:
<RootObject>
<SalesOrderLineRet />
<SalesOrderLineGroupRet />
</RootObject>
Using [XmlElement(typeof(T))] tells XmlSerializer that the list should be serialized without an outer container element, and that items of type T can be expected to be found in the list. You must apply [XmlElement(typeof(T))] once for each type T that will be stored in the list.
(You can use List<object> if the types in the list have no other more derived base type, however I don't recommend that. I would instead recommending grouping the possible types of list entry under a specific base type.)
If you would prefer your list to be serialized with an outer container element, you can use [XmlArray] and [XmlArrayItem(typeof(T))]:
public abstract class SalesOrderLineRetBase
{
}
public class SalesOrderLineRet : SalesOrderLineRetBase
{
}
public class SalesOrderLineGroupRet : SalesOrderLineRetBase
{
}
public class RootObject
{
[XmlArray("SalesOrders")]
[XmlArrayItem(typeof(SalesOrderLineRetBase))]
[XmlArrayItem(typeof(SalesOrderLineRet))]
[XmlArrayItem(typeof(SalesOrderLineGroupRet))]
public List<SalesOrderLineRetBase> SalesOrders { get; set; }
}
Which produces the following XML:
<RootObject>
<SalesOrders>
<SalesOrderLineRet />
<SalesOrderLineGroupRet />
</SalesOrders>
</RootObject>
You must apply [XmlArrayItem(typeof(T))] for each type T that will be stored in the list.
(Since you don't include the relevant classes and XML in your question, I'm not sure which one you might want.)
Update: solved! It seems like Json.NET does include derived type properties by default, but they were not included because of an error in my code where the derived type was overwritten by a base type.
I am currently working on a project for school, and I stumbled upon a problem.
I need to serialize an object to Json, which I do using Newtonsoft Json.NET. The object I am trying to serialize has a List of objects of a certain base class, but the objects in that List are of derived types with their own unique properties.
Currently, only the properties of the base class are included in the resulting Json. If it's possible, I'd like the Json converter to detect of which derived class the objects in the collection are, and to serialize their unique properties.
Below some code as an example of what I'm doing.
Classes I use:
public class WrappingClass
{
public string Name { get; set; }
public List<BaseClass> MyCollection { get; set; }
}
public class BaseClass
{
public string MyProperty { get; set; }
}
public class DerivedClassA : BaseClass
{
public string AnotherPropertyA { get; set; }
}
public class DerivedClassB : BaseClass
{
public string AnotherPropertyB { get; set; }
}
Serializing some dummy objects:
WrappingClass wrapperObject = new WrappingClass
{
Name = "Test name",
MyCollection = new List<BaseClass>();
};
DerivedClassA derivedObjectA = new DerivedClassA
{
MyProperty = "Test my MyProperty A"
AnotherPropertyA = "Test AnotherPropertyA"
};
DerivedClassB derivedObjectB = new DerivedClassB
{
MyProperty = "Test my MyProperty B"
AnotherPropertyB = "Test AnotherPropertyB"
};
wrapperObject.MyCollection.Add(derivedObjectA);
wrapperObject.MyCollection.Add(derivedObjectB);
var myJson = JsonConvert.SerializeObject(wrapperObject);
The Json that would currently be generated:
{"Name":"Test name","MyCollection":[{"MyProperty":"Test my MyProperty A"}{"MyProperty":"Test my MyProperty B"}]}
The Json I want:
{"Name":"Test name","MyCollection":[{"MyProperty":"Test my MyProperty A","AnotherPropertyA":"Test AnotherPropertyA"},{"MyProperty":"Test my MyProperty B","AnotherPropertyB":"Test AnotherPropertyB"}]}
Any ideas? Thank you!
The default behavior of json.NET is to include all properties on derived types. The only reason you would not be getting them is if you have defined a [DataContract] on the base type which you have not extended to your derived types or if you have something like optin serialization ect.
Decorate the properties with Ignore attribute if you dont want them serialized like
public class DerivedClassA : BaseClass
{
[JsonIgnore]
public string AnotherPropertyA { get; set; }
}
I am trying to serialize an object in a particular manner. The main class has a container class that holds some attributes, but really these attributes should be on the main class, from the point of view of the schema. Is there a way to bypass the container class and treat the properties on the container class as properties on the main class, for the purposes of serialization?
I am trying to create XML along the lines of:
<Main foo="3" bar="something">
<Others>etc</Others>
</Main>
from this code:
[System.Xml.Serialization.XmlRootAttribute("Main", Namespace = "")]
public class MainObject
{
public HelperContainer { get; set; }
public string Others { get; set; }
}
public class HelperContainer
{
[System.Xml.Serialization.XmlAttributeAttribute(AttributeName = "foo")]
public int Foo { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute(AttributeName = "bar")]
public string Bar { get; set; }
}
You may want to try implementing IXmlSerializable on MainObject to be able to control what happens when calling serialize. For the read and write xml methods specify the fields to serialize.
Check out msdn: http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
Something like:
public class MainObject : IXmlSerializable
{
public HelperContainer { get; set; }
public string Others { get; set; }
public void WriteXml (XmlWriter writer)
{
writer.WriteString(Others);
writer.WriteAttributeString("foo", HelperContainer.Foo);
writer.WriteAttributeString("bar", HelperContainer.Bar);
}
public void ReadXml (XmlReader reader)
{
Others = reader.ReadString();
//...
}
}