Error in Deserializing XML in compact framework - winforms

I have created a project in .net CF 3.5 another project creates an XML files which I will be using in CF project which is in Winform.I am using VS2012.
While deserializing the XML I am getting invalid operation exception.
The class which does the deserialization is a simple one
class DeserOp
{
byte[] contentBytes = Properties.Resources.test; //The test is xml file I put in resources for simplicity
XmlSerializer serializer = new XmlSerializer(typeof(Vision));
MemoryStream stream = new MemoryStream(contentBytes);
Vision myClass = (Vision)serializer.Deserialize(stream);
}
Class Vision will be :
public class Vision
{
[XmlArrayItem(Type = typeof(Mercedes)),
XmlArrayItem(Type = typeof(BMW))]
public List<Cars> ItemArray { get; set; }
public Vision() { ItemArray = new List<Cars>(); }
}
Class Cars will be:
public class Cars
{
string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
}
}
}
public string _type;
public string Type
{
get { return _type; }
set
{
if (_type != value)
{
_type = value;
}
}
}
}
Class Mercedes/BMW will be:
public class Mercedes : Cars
{
string _make;
public string Make
{
get { return _make; }
set
{
if (_make != value)
{
_make = value;
}
}
}
}
The XML test will be:
The XML will be look alike:
<?xml version="1.0" encoding="utf-8"?>
<Vision xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ItemArray>
<Mercedes>
<Name>ABC</Name>
<Type>Luxery</Type>
<Make>Cclass</Make>
</Mercedes>
<BMW>
<Name>BDD</Name>
<Type>Sedan</Type>
<Make>Perfect</Make>
</BMW>
</ItemArray>
</Vision>
I tried all possible attributes also like [XmlIncludeAttribute(typeof(Mercedes))] on a class Car but still it is throwing error.
Also all the elements are public and the file also has public access.

Related

Map a Uri field using Dapper

What is the cleanest way to map a string column to a Uri property using Dapper?
Here's the cleanest I've been able to come up with so far (using the ITypeMap functionality):
Query:
SELECT * FROM TableWithAStringAddressColumn
POCO:
public class MyPoco
{
[ColumnSetter("DapperAddress")]
public Uri Address { get; set; }
private string DapperAddress { set { this.Address = new Uri(value); } }
}
Extensions:
partial class SqlMapper
{
public static void InitializeTypeMaps()
{
SqlMapper.SetTypeMap(
typeof(MyPoco),
new CustomPropertyTypeMap(typeof(MyPoco), SqlMapper.CustomSetterMapper));
// call out every other class that needs this kind of mapping
}
public static Func<Type, string, PropertyInfo> CustomSetterMapper =
(type, columnName) =>
{
PropertyInfo prop = type
.GetProperties()
.FirstOrDefault(p => string.Equals(columnName, p.Name, StringComparison.OrdinalIgnoreCase));
if (prop != null)
{
// find out if we need to use a different setter
ColumnSetterAttribute setterAttribute = prop.GetCustomAttributes(false).OfType<ColumnSetterAttribute>().LastOrDefault();
if (setterAttribute != null)
{
PropertyInfo setterProp = type
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => string.Equals(setterAttribute.Setter, p.Name, StringComparison.OrdinalIgnoreCase));
if (setterProp == null)
{
throw new InvalidOperationException(string.Format("Setter property misconfigured (Property={0}, Setter={1})", prop.Name, setterAttribute.Setter));
}
else
{
prop = setterProp;
}
}
}
return prop;
};
}
Custom Attribute:
public class ColumnSetterAttribute : Attribute
{
public string Setter { get; set; }
public ColumnSetterAttribute(string setter)
{
this.Setter = setter;
}
}
[edit] I'm looking for a solution I can use without needing to call out all columns in all my queries (I'd like to find a solution where I can use SELECT *).
Seems like a lot of work...
Wouldn't this be ok?
public class MyPoco
{
private string _uriMapper;
public Uri SomeUri
{
get { return new Uri(_uriMapper); }
}
public string Mapper { set { _uriMapper = value; } }
}
Edit:
public class UriContainer
{
private string _uriMapper;
public string UriMapper { set { _uriMapper = value; } }
public int Id { get; set; }
public Uri SomeUri { get {return new Uri(_uriMapper);} }
}
public class DbTests
{
[Test]
public void Can_Get_A_Uri()
{
using (var c = new SqlConnection("hello"))
{
c.Open();
var uri = c.Query<UriContainer>("select *, someuri as urimapper from uris where id = 3").Single();
Console.WriteLine(uri.SomeUri);
}
}
}

Single element array in WCF RESTful JSON web service client

I'm trying to consume a RESTful JSON web service using WCF on the client side. The service is 3rd party, so I cannot make any changes to the server response.
The server is sending back a response that looks something like this when there's only one data point...
Single Data Point
{
"Data":
{
"MyPropertyA":"Value1",
"MyPropertyB":"Value2"
},
}
and something like this when there's more than one data point...
Multiple Data Points
{
"Data":
[
{
"MyPropertyA":"Value1",
"MyPropertyB":"Value2"
},
{
"MyPropertyA":"Value3",
"MyPropertyB":"Value4"
},
{
"MyPropertyA":"Value5",
"MyPropertyB":"Value6"
}
],
}
I have my service contract set up like this...
[ServiceContract]
public interface IRewardStreamService
{
[OperationContract]
[WebInvoke]
MyResponse GetMyStuff();
}
and a data point's data contract like this...
[DataContract]
public class MyData
{
[DataMember]
public string MyPropertyA { get; set; }
[DataMember]
public string MyPropertyB { get; set; }
}
and the only way I can get the single data point response to work is if I have a single instance property like this, but this does not parse the multiple data point response...
Response for Single Instance
[DataContract]
public class MyResponse
{
[DataMember]
public MyData Data { get; set; }
}
and the only way I can get the multiple data point response to work is if I have an array / list instance property like this, but this does not parse the single data point response...
Response for Multiple Instance
[DataContract]
public class MyResponse
{
[DataMember]
public IList<MyData> Data { get; set; }
}
I understand the issue is that the response is omitting the brackets when there's only one data point returned, but it seems that WCF doesn't play well with deserializing that syntax. Is there some way I can tell the DataContractJsonSerializer to allow single element arrays to not include brackets and then tell my service to use that serializer? Maybe a service behavior or something?
Any direction would be helpful.
You can use a custom message formatter to change the deserialization of the JSON into the data contract you want. In the code below, the data contract is defined to have a List<MyData>; if the response contains only one data point, it will "wrap" that into an array prior to passing to the deserializer, so it will work for all cases.
Notice that I used the JSON.NET library to do the JSON modification, but that's not a requirement (it just has a nice JSON DOM to work with the JSON document).
public class StackOverflow_12825062
{
[ServiceContract]
public class Service
{
[WebGet]
public Stream GetData(bool singleDataPoint)
{
string result;
if (singleDataPoint)
{
result = #"{
""Data"":
{
""MyPropertyA"":""Value1"",
""MyPropertyB"":""Value2""
},
}";
}
else
{
result = #"{
""Data"":
[
{
""MyPropertyA"":""Value1"",
""MyPropertyB"":""Value2""
},
{
""MyPropertyA"":""Value3"",
""MyPropertyB"":""Value4""
},
{
""MyPropertyA"":""Value5"",
""MyPropertyB"":""Value6""
}
],
} ";
}
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
}
[DataContract]
public class MyData
{
[DataMember]
public string MyPropertyA { get; set; }
[DataMember]
public string MyPropertyB { get; set; }
}
[DataContract]
public class MyResponse
{
[DataMember]
public List<MyData> Data { get; set; }
public override string ToString()
{
return string.Format("MyResponse, Data.Length={0}", Data.Count);
}
}
[ServiceContract]
public interface ITest
{
[WebGet]
MyResponse GetData(bool singleDataPoint);
}
public class MyResponseSingleOrMultipleClientReplyFormatter : IClientMessageFormatter
{
IClientMessageFormatter original;
public MyResponseSingleOrMultipleClientReplyFormatter(IClientMessageFormatter original)
{
this.original = original;
}
public object DeserializeReply(Message message, object[] parameters)
{
WebBodyFormatMessageProperty messageFormat = (WebBodyFormatMessageProperty)message.Properties[WebBodyFormatMessageProperty.Name];
if (messageFormat.Format == WebContentFormat.Json)
{
MemoryStream ms = new MemoryStream();
XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(ms);
message.WriteMessage(jsonWriter);
jsonWriter.Flush();
string json = Encoding.UTF8.GetString(ms.ToArray());
JObject root = JObject.Parse(json);
JToken data = root["Data"];
if (data != null)
{
if (data.Type == JTokenType.Object)
{
// single case, let's wrap it in an array
root["Data"] = new JArray(data);
}
}
// Now we need to recreate the message
ms = new MemoryStream(Encoding.UTF8.GetBytes(root.ToString(Newtonsoft.Json.Formatting.None)));
XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(ms, XmlDictionaryReaderQuotas.Max);
Message newMessage = Message.CreateMessage(MessageVersion.None, null, jsonReader);
newMessage.Headers.CopyHeadersFrom(message);
newMessage.Properties.CopyProperties(message.Properties);
message = newMessage;
}
return this.original.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw new NotSupportedException("This formatter only supports deserializing reply messages");
}
}
public class MyWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
IClientMessageFormatter result = base.GetReplyClientFormatter(operationDescription, endpoint);
if (operationDescription.Messages[1].Body.ReturnValue.Type == typeof(MyResponse))
{
return new MyResponseSingleOrMultipleClientReplyFormatter(result);
}
else
{
return result;
}
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new WebHttpBinding(), new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new MyWebHttpBehavior());
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.GetData(false));
Console.WriteLine(proxy.GetData(true));
Console.Write("Press ENTER to close the host");
((IClientChannel)proxy).Close();
factory.Close();
Console.ReadLine();
host.Close();
}
}
I don't know about using WCF so I'll change to Asp.Net WCF. Here is an article that will get you one the way
http://www.west-wind.com/weblog/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing
I just can't figure out how to determine if it's an array or a single object. Here is a little code.
[TestMethod]
public void SingleObject()
{
using (var client = new HttpClient())
{
var result = client.GetStringAsync("http://localhost:8080/api/JSONTestOne");
string content = result.Result;
JObject jsonVal = JObject.Parse(content);
dynamic aFooObj = jsonVal;
Console.WriteLine(aFooObj.afoo.A);
}
}
[TestMethod]
public void ArrayWithObject()
{
using (var client = new HttpClient())
{
var result = client.GetStringAsync("http://localhost:8080/api/JSONTest");
string content = result.Result;
JObject jsonVal = JObject.Parse(content);
dynamic foos = jsonVal;
Console.WriteLine(foos[0].A);
}
}

Passing a list or array to RESTeasy using get

I've seen this kind of thing described in various examples showing how to create a REST service which takes arrays or a list of objects as part of the URL.
My question is, how to implement this using RESTeasy?
Something like the following would be how i would assume this to work.
#GET
#Path("/stuff/")
#Produces("application/json")
public StuffResponse getStuffByThings(
#QueryParam("things") List<Thing> things);
Create a StringConverter and a use a wrapper object. Here is a quick and dirty example:
public class QueryParamAsListTest {
public static class Thing {
String value;
Thing(String value){ this.value = value; }
}
public static class ManyThings {
List<Thing> things = new ArrayList<Thing>();
ManyThings(String values){
for(String value : values.split(",")){
things.add(new Thing(value));
}
}
}
static class Converter implements StringConverter<ManyThings> {
public ManyThings fromString(String str) {
return new ManyThings(str);
}
public String toString(ManyThings value) {
//TODO: implement
return value.toString();
}
}
#Path("/")
public static class Service {
#GET
#Path("/stuff/")
public int getStuffByThings(
#QueryParam("things") ManyThings things){
return things.things.size();
}
}
#Test
public void test() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getProviderFactory().addStringConverter(new Converter());
dispatcher.getRegistry().addSingletonResource(new Service());
MockHttpRequest request = MockHttpRequest.get("/stuff?things=a,b,c");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assert.assertEquals("3", response.getContentAsString());
}
}
I think you can also use a StringParamUnmarshaller
I had some luck with this, using Collection rather than List. I was unable to make a StringConverter for List work.
#Provider
public class CollectionConverter implements StringConverter<Collection<String>> {
public Collection<String> fromString(String string) {
if (string == null) {
return Collections.emptyList();
}
return Arrays.asList(string.split(","));
}
public String toString(Collection<String> values) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (String value : values) {
if (first) {
first = false;
} else {
sb.append(",");
}
sb.append(value);
}
return sb.toString();
}
}
I did the toString from my head. Be sure to write unit tests for it to verify. But of course, everything is easier and clearer when you use Guava. Can use Joiner and Splitter. Really handy.
Just use a wrapper on its own, no need for anything else.
In your endpoint
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Path("/find")
#GET
MyResponse find(#QueryParam("ids") Wrapper ids);
And you wrapper looks like this :
public class Wrapper implements Serializable {
private List<BigInteger> ids = Collections.emptyList();
public String toString() {
return Joiner.on(",")
.join(ids);
}
public List<BigInteger> get() {
return ids;
}
public Wrapper(String s) {
if (s == null) {
ids = Collections.emptyList();
}
Iterable<String> splitted = Splitter.on(',')
.split(s);
Iterable<BigInteger> ids = Iterables.transform(splitted, Functionz.stringToBigInteger);
this.ids = Lists.newArrayList(ids);
}
public Wrapper(List<BigInteger> ids) {
this.ids = ids;
}
}

Why can't I add attributes when serializing ObservableCollection<T>?

I'm trying to extend an ObservableCollection with a few custom properties and have it serialize. However, I can't seem to get it to serialize these properties. I'm using .NET 4.0 where they fixed the serialization issues of ObservableCollection, but am still having problems. My hunch is that GetObjectData is being called on the base class and not mine. Any ideas?
[Serializable]
[XmlRoot(ElementName = "MyCollection")]
public class MyCollection : ObservableCollection<MyItem>, ISerializable
{
private string name;
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
}
private MyCollection()
{
Name = string.Empty;
}
public MyCollection(string name)
{
Name = name;
}
public MyCollection(SerializationInfo info, StreamingContext context)
{
Name = (string)info.GetValue("Name", typeof(string));
}
[XmlAttribute]
public string Name
{
get { return name; }
protected set
{
string originalName = name;
name = value;
if (originalName != name)
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
public void SaveToFile(string path)
{
string directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
XmlSerializer serializer = new XmlSerializer(typeof(MyCollection));
using (TextWriter textWriter = new StreamWriter(path))
{
serializer.Serialize(textWriter, this);
textWriter.Close();
}
}
public static MyCollection LoadFromFile(string path)
{
XmlSerializer deserializer = new XmlSerializer(typeof(MyCollection));
using (TextReader textReader = new StreamReader(path))
{
MyCollection myCollection = (MyCollection)deserializer.Deserialize(textReader);
textReader.Close();
return myCollection;
}
}
}
XML Serialization does not support this scenario. You simply cannot add anything to a class implementing ICollection.
If you require this, then you will have to implement IXmlSerializable and do the work yourself.
Note that you may be confusing XML Serialization with runtime serialization. XML Serialization doesn't care about the [Serializable] attribute or GetObjectData, etc.

property names are different from original Object in the silverlight

Following is part of service layer which is provided by WCF service :
[Serializable]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
public class Service1 : IService1
{
public List<WaitInfo> GetWaitingList()
{
MyDBDataContext db = new MyDBDataContext();
var query = from w in db.WAIT_INFOs
select new WaitInfo
{
TagNo = w.PATIENT_INFO.TAG_NO,
RoomName= w.ROOM_INFO.ROOM_NAME,
PName= w.PATIENT_INFO.P_NAME
};
List<WaitInfo> result = query.ToList();
return result;
}
And following is codebehind part of UI layer which is provided by Silverlight
public MainPage()
{
InitializeComponent();
Service1Client s = new Service1Client();
s.GetWaitingListCompleted +=
new EventHandler<GetWaitingListByCompletedEventArgs>( s_GetWaitingListCompleted);
s.GetWaitingListAsync();
}
void s_GetWaitingListCompleted(object sender,
RadControlsSilverlightApplication1.ServiceReference2.GetWaitingListByCompletedEventArgs e)
{
GridDataGrid.ItemsSource = e.Result;
}
And following is xaml code in Silverlight page
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="GridDataGrid"></data:DataGrid>
</Grid>
It is very simple code, however what I am thinking weird is property name of object at "e.Result" in the code behind page.
In the service layer, although properties' names are surely "RoomName, PName, TagNo", in the silverlight properties' names are "roomName, pName, tagNo" which are private variable name of the WaitingList Object.
Did I something wrong?
Thanks in advance.
Unless you specifically decorate your class with the DataContract attribute (which you should, instead of Serializable) then a default DataContract will be inferred. For normal Serializable types, this means the fields will be serialized as opposed to the properties.
You can markup your class in either of the following two ways. The latter will use the property accessors when serializing/deserializing your object which may be very useful or be a hassle depending on your circumstances.
[DataContract]
public class WaitInfo
{
[DataMember(Name="RoomName")]
private string roomName;
[DataMember(Name="PName")]
private string pName;
[DataMember(Name="TagNo")]
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
The method I prefer:
[DataContract]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
[DataMember]
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
[DataMember]
public string PName
{ get { return pName; } set { this.pName = value; } }
[DataMember]
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}

Resources