I have an issue generating proper XML/JSON with my WebService, when handling simpleContent tags in the XSD.
First of all, I only have an XSD file (no WSDL), with this content (simplified) :
<xs:complexType name="VerticalDataValue">
<xs:simpleContent>
<xs:extension base="NCADevicePublication:Double">
<xs:attribute name="unit" type="NCADevicePublication:VerticalUnitEnum" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="Double">
<xs:restriction base="xs:double" />
</xs:simpleType>
<xs:simpleType name="VerticalUnitEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="ft"></xs:enumeration>
<xs:enumeration value="m"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
I then generate my class using Xsd.exe.
What I expect for this structure, on the XML output:
<altitudeCoordinate unit="ft">2.1</altitudeCoordinate>
What I get :
<altitudeCoordinate>
<Value>2.1</Value>
<unit>ft</unit>
<unitSpecified>true</unitSpecified>
</altitudeCoordinate>
The same for JSON, I expect :
"altitudeCoordinate": {
"#unit": "ft",
"text": "2.1"
}
But I get :
"altitudeCoordinate":{
"unit": "ft",
"unitSpecified": "true,
"Value": 2.1
I saw on MSDN that the simpleContent restriction is not recognized by Xsd.Exe.
Is there any way to have this kind of "standard" output or .Net just cannot do it?
Thanks
UPDATE
I was able to make it work for my WCF Service. The solution was quite simple... just put [XmlSerializerFormat] at the top of the Interface, and voilĂ .
The reason is that the default serializer (DataContractSerializer) cannot handle xml attributes correctly.
Also, be aware that WCFStorm uses the DataContractSerializer as well : I discovered that even when using the XmlSerializer, I had bad XML in WCFStorm. I then checked with SoapUI, and it was working! (lost a few hours still).
So now, let's make this work on my Web API project, for JSON....
Finally I figured a solution. Just a reminder : my goal was not to touch at the generated class.
For SOAP/XML
As stated in my update, the solution was pretty easy, I just put the following attribute on the WCF interface :
[XmlSerializerFormat]
For REST/JSON
The solution was to define MetadataType classes for the "bothering" classes that were not well converted.
For example, here is how the VerticalDataValue class is defined in the auto-generated file (I stripped the attributes and namespaces):
public partial class VerticalDataValue {
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public VerticalUnitEnum unit;
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool unitSpecified;
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public double Value;
}
I created another file, containing all MetadataType classes, defined like following:
[MetadataType(typeof(VerticalDataValueMetaClass))]
public partial class VerticalDataValue { }
public class VerticalDataValueMetaClass
{
[JsonProperty("#unit")]
public VerticalUnitEnum unit;
[JsonIgnore]
public bool unitSpecified
[JsonProperty("text")]
public double value;
}
Be aware that this is only possible if your base class is partial.
Of course, this is high-maintenance code, but at least this does not mess with the auto-generated class.
Related
I have classes generated via xsd.exe (xsd.exe someschema.xsd /classes). One of the nodes is declared as an element:
<xs:element name="containsxmlelementsbeneath"/>
As the (ficticious) name implies, it looks like this:
<containsxmlelementsbeneath>
<somemore>
...
</somemore>
</containsxmlelementsbeneath>
When it is deserialized, I see in the debugger that it is of type
System.Xml.XmlNode[]
I can force it in the Immediate Window
?((System.Xml.XmlNode[])elem.containsxmlelementsbeneath)[0].InnerXml
I got no IntelliSense, which made sense when I tried the snippet in my code - the class seems to have been removed from the WinRT profile - which is nice if all you need is Windows.Data.Xml.Dom.IXmlNode - but not in this case.
How can I go and get the string representation of that element? Is there a way to "fix" the xsd.exe-generated output so it uses Windows.Data.Xml.Dom for Serialization? (doesn't look like it to me)
Did I hit a fringe case they didn't think about?
Update - tried the following (I know, an abuse of dynamic):
dynamic x = elem.containsxmlelementsbeneath;
string s = x[0].InnerXml;
This yields "The API 'System.Xml.XmlNode[]' cannot be used on the current platform."
I had a (longer) chat with another dev - after some trial and error we came up with a solution:
<xs:element ref="containsxmlelementsbeneath"/>
<xs:element name="containsxmlelementsbeneath">
</xs:element>
This creates an empty class for us (via xsd.exe)
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class containsxmlelementsbeneath
{
}
This has to be modified like this:
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class containsxmlelementsbeneath : IXmlSerializable
{
[XmlIgnore]
public string Text { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
throw new System.NotImplementedException();
}
public void ReadXml(System.Xml.XmlReader reader)
{
Text = reader.ReadInnerXml();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
throw new System.NotImplementedException();
}
}
Note that all attributes except XmlRoot have to be removed, otherwise you get Reflection Exceptions (Only XmlRoot attribute may be specified for the type containsxmlelementsbeneath. Please use XmlSchemaProviderAttribute to specify schema type.)
End Result: this node with all its subnodes as a plain old string. No non-accesible XmlNode or XmlElement any more...
Does anyone know if Spring has any extensions that allow for configuring its ApplicationContext via JSON (or really any other format) rather than XML? I couldn't find anything in the official docs, but I was wondering if there were any other open source extensions that could allow this.
Just to be clear, I'm not talking about configuring SpringMVC to set up a RESTful JSON-based web service or anything like that, just if it's possible to do Spring app configuration via JSON instead of XML.
As far as I know there is no project to support JSON as configuration source. It should be relatively easy to kick-start, (Spring container has no dependency on XML, it is just a way to construct bean definitions). However it is much more work than you might think.
Note that Spring provides xml-schema to assist you in writing correct XML. You won't get that much in JSON. Also many DSLs were built on top of Spring XML and custom namespaces support (spring-integration, mule-esb and others use it).
If you hate XML (many do), try out Java Configuration, available since 3.0 and improved in 3.1:
#Configuration
public class MyBeans {
#Bean
public Foo foo() {
return new Foo();
}
#Bean
public Bar bar() {
return new Bar(foo());
}
#Bean
public Buzz buzz() {
Buzz buzz = new Buzz();
buzz.setFoo(foo());
return buzz;
}
}
Interesting fact: thanks to some fancy proxying, foo() is called exactly once here, even though referenced twice.
Try JSConf library available on maven central, it's support Properties, HOCON and JSON format.
You can inject values from external file to your service and more !
Sample usage of JavaConfig :
You data stored on file app.conf
{
"root":{
"simpleConf":{
"url":"Hello World",
"port":12,
"aMap":{
"key1":"value1",
"key2":"value2"
},
"aList":[
"value1",
"value2"
]
}}
You service where your configuration must be inject
#Service("service")
public class Service {
#Autowired
private ConfigBean configBean;
}
Declare a interface to access your configuration values from your service
#ConfigurationProperties("root/simpleConf")
public interface ConfigBean {
String getUrl();
int getPort();
Map getAMap();
List getAList();
}
And your Spring configuration bean :
#Configuration
public class ContextConfiguration {
#Bean
public static ConfigurationFactory configurationFactory() {
return new ConfigurationFactory().withResourceName("app.conf") //
.withScanPackage("org.jsconf.core.sample.bean");
}
}
I have an ASP.NET 3.5 SP1 web application that uses a custom JavaScriptConverter. The code used to work at some time in the past, but has stopped working. I do not know what changes have happened in the middle server side. The problem we are seeing now is that the converter is not being invoked, so we are getting errors that System.Data.DataRow cannot be serialized.
The following is the relevant portion of web.config:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="DataSetConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataSetConverter, Microsoft.Web.Preview" />
<add name="DataRowConverter" type="WebUI.DataRowConverter, WebUI.DataRowConverter, Version=1.1.0.323, Culture=neutral" />
<add name="DataTableConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataTableConverter, Microsoft.Web.Preview" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
A trimmed version of the class is as follows (trimmed only to avoid wasting space on unnecesary implementation):
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Web.Script.Serialization;
namespace WebUI {
public class DataRowConverter : JavaScriptConverter {
private ReadOnlyCollection<Type> _supportedTypes = new ReadOnlyCollection<Type>(new Type[] { typeof(DataRow) });
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) {
// stuff
return dr;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) {
// stuff
return dictionary;
}
public override IEnumerable<Type> SupportedTypes {
get {
return this._supportedTypes;
}
}
}
}
What seems to happen is that the class is indeed being loaded (if we take it out of web.config and the project references, no breakpoints are available; put it back into web.config and copy the DLL/PDB by hand or add it to the project, breakpoints are available), but it's not being used propertly. No breakpoint anywhere in the class is hit, and no exceptions (including one thrown in a constructor added to see what happens) are thrown. It seems like the class is being loaded but never called.
This is on IIS 7.5 and IIS 7.0 in Integrated mode, if it matters.
Anyone have any ideas?
OK, just in case anyone else hits this, when calling web services through the automatically generated test pages, the custom serializers are not invoked - they are bypassed. This is apparently by design.
I'm really stumped on this incredibly simple mapping. It looks just like one of the examples even. If I comment out the internal structure, it'll run the binding compiler successfully. If I put the internal structure back in, it fails. Note that the internal structure is just defining the XML. This is basically example5 of the JIBX tutorial examples.
<binding>
<mapping name="RequestTransaction" class="TransactionRequest">
<value name="version" set-method="setVersion" get-method="getVersion" style="attribute" />
<structure name="transHeader">
<value name="requestCount" set-method="setRequestCount" get-method="getRequestCount"/>
</structure>
</mapping>
<binding>
Then I get the following error on the jibx compile:
Error: Error during validation: null; on mapping element at (line 2, col 97, in jibx-binding.xml)
I'm absolutely stumped and out of ideas. Google shows nothing useful.
The <structure> is arguably the most important concept in JiBX binding because it allows you to map arbitrary XML to your Java classes without forcing you to create bloated and ugly layers of nested Java objects and classes to match the XML design.
In this case your binding declares that you have an XML element named <transHeader> that will not be present in your Java class.
With some slight fixes to your XML format, your binding works perfectly. I assume the fact that your binding has two <binding> open tags rather than and open and close <binding></binding> is a typo, because you said you got it to work without the structure. Also add <?xml version="1.0"?> at the top of your binding file. Those two XML mods allow the JiBX 1.2 binding compiler to work with the following Java class:
(Note: you didn't provide the Java class this binding is for so I had to reconstruct it from the info you put in the binding file. The obvious side effect of this is that I reconstructed a class that will work with this binding. But the simple fact is that a JiBX binding by design contains all the info you need to know about the class and the XML.)
public class TransactionRequest {
private String version;
private int requestCount;
public void setVersion(String ver) {
version = ver;
}
public String getVersion() {
return version;
}
public void setRequestCount(int count) {
requestCount = count;
}
public int getRequestCount() {
return requestCount;
}
}
compile the class then run the binding compiler with:
>java -jar jibx-bind.jar jibx-binding.xml
To test it I used the following sample.xml:
(Note: you also didn't provide the XML you are trying to map so again I created a sample based on what you did provide)
<?xml version="1.0"?>
<RequestTransaction version="0.1">
<transHeader>
<requestCount>3</requestCount>
</transHeader>
</RequestTransaction>
Running the test uses the following code:
public static void main(String[] argz) {
String fileName = "./sample.xml";
IBindingFactory bfact = null;
IUnmarshallingContext uctx = null;
TransactionRequest sample = null;
try {
bfact = BindingDirectory.getFactory(TransactionRequest.class);
uctx = bfact.createUnmarshallingContext();
InputStream in = new FileInputStream(fileName);
sample = (TransactionRequest)uctx.unmarshalDocument(in, null);
System.out.println(sample.getRequestCount());
System.out.println(sample.getVersion());
}
catch (Exception e) {
e.printStackTrace();
}
}
And it runs successfully.
It's been a while now, but I found it was related to inheritance. I needed to give mappings for everything in the inheritance tree, including interfaces as I recall.
I ended up creating a wrapper object, which I've found seems to be the easiest way to use JIBX in general. Trying to map a true domain class causes tendrils into every class that class touches and I have to unjar everything so JIBX can find the classes, including 3rd party libs.
I have been trying out both Linq to Sql and EF in my ASP.NET MVC application. After switching to EF I realized my XML/JSON serialization output has extra cruft.
XML:
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<EntityKey>
<EntitySetName>Persons</EntitySetName>
<EntityContainerName>PersonEntities</EntityContainerName>
<EntityKeyValues>
<EntityKeyMember>
<Key>Id</Key>
<Value xsi:type="xsd:int">1</Value>
</EntityKeyMember>
</EntityKeyValues>
</EntityKey>
<Id>1</Id>
<Name>John</Name>
</Test>
JSON:
{"Id":1,"Name":"John","EntityState":2,"EntityKey"{"EntitySetName":"Persons","EntityContainerName":"PersonEntities","EntityKeyValues":[{"Key":"Id","Value":1}],"IsTemporary":false}}
Instead I would just like my output to be:
{"Id":1, "Name":"John"}
My EF query to retrieve the object is:
Tests.First(t => t.Id == testId);
You can shape the JSON result in your controller like this:
public JsonResult Person(int id)
{
var person = PersonRepository.FindByID(id);
var result = new { Id = person.Id, Name = person.Name };
return Json(result);
}
This will limit the DTO which is serialized to contain only the values you want.
Edit:
As a paritial answer to your comment question; you can create a simpler PersonViewModel class (DTO) that you can map the properties to. As John Saunders mentioned in his answer Automapper is a nice way to simplify the copying of the property values out of the EF Person instance:
The modified Action method may look like this:
public JsonResult Person(int id)
{
var person = PersonRepository.FindByID(id);
var dto = Mapper.Map<Person, PersonViewModel>(person);
return Json(dto);
}
The only other option I can think of is to use reflection to modify the DataMemberAttributes on the Person entity to suppress the EntityKey property.
Another approach to work around this is to use the JavascriptSerializer's ScriptIgnore attribute and create a partial class for the object in question, new'ing up the EntityKey, EntityState properties and adding a ScriptIgnore attribute to them:
public partial class Person
{
[ScriptIgnore]
public new System.Data.EntityKey EntityKey { get; set; }
[ScriptIgnore]
public new System.Data.EntityState EntityState { get; set; }
}
When the Person class is serialized via JavascriptSerializer, it will ignore those properties. However, this would not be practical because EF uses the state info to keep track of objects and this would wreak havoc.
If there were a way to dynamically add properties, it would eliminate the need to override those properties just to add a [ScriptIgnore] attribute. But, since there is no way to dynamically add attributes, this solution may not be that useful.
So far, the best technique I've found involves code generation. I did this on one project that was using the Service Factory, but you could do the same "by hand" using T4 Text templates directly.
Also, keep an eye on AutoMapper. It's still new enough that I consider it to be emerging technology, but I'm hoping it will emerge soon!