JSON serialization with odd characters - c#

There is an application that was originally written in Ruby on Rails that provides API services to several mobile applications; management has decided to add the functionality of the RoR service to the main .NET-based project. OK, no big deal, we'll just duplicate the service calls in WebAPI right? How difficult can it be?
Apparently somebody on the Ruby side thought it would be a swell idea to put extra characters into the api response objects. I'm seeing things like:
{
...
{"enabled?":true}
...
}
...so here I am, shaking my head at this, and hoping there is a technique to serialize .NET objects into JSON where variable names have question marks and whatnot. Is there a way to do this, or are we going to have to build custom serializers for each of these objects? Changing the mobile apps to consume more platform-friendly JSON is really not desirable at this point. We use JSON.Net, but if there's another way to do this, it'd be OK.

In your c# object, give your property a valid name (such as Enabled in this case) and then specify the JSON property name in the Name property of a DataMember attribute, or the PropertyName property of a JsonProperty attribute:
[DataContract]
public class MyClass
{
[DataMember(Name="enabled?")]
public bool Enabled { get; set; }
}
Or
public class MyClass
{
[JsonProperty("enabled?")]
public bool Enabled { get; set; }
}
If you use DataMemberAttribute, don't forget to add the DataContract attribute, and that data contract serialization is opt-in, so you'll need to add DataMember to all the attributes you want to serialize. Having done so, however, you'll gain compatibility with the DataContractSerializers, which might be useful down the road.

Related

DisplayAttribute name property not working in Silverlight

I am binding DataGrid.ItemsSource property to the List<PersonDetails> object. I am getting datas through Silverlight-enabled WCF Service. So the PersonDetails class is implemented in Web Project. Each DataGrid's header text is changing as i want if the class is located in Silverlight project. But then I can not use this class in the web service. The only solution is to add same class in to the both of the projects. But, is there any other way?
The class looks like that:
[DataContract]
public class PersonGeneralDetails
{
// Properties
[DataMember]
[DisplayAttribute(Name = "Sira")]
public int RowNumber { get; set; }
[DataMember]
[DisplayAttribute(Name = "Seriyasi")]
public string SerialNumber { get; set; }
}
It seems attributes aren't generated in web project. I know that I can change header text using DataGrid events. But i want to make it work using attributes.
The problem is the WCF DataContract is an inter-operable mechanism that can be used across languages and platforms.
If you take a look to serialized data generated by the DataContractSerializer (or its code in System.Runtime.Serialization.dll, specifically InternalWriteObjectXyz() methods) you'll see that it merely serializes values into a simple XML message. Nothing related to .NET Framework will be there so all kind of attributes, both custom and compiler generated, will be stripped out and won't even received by the client.
It works creating a copy of your data and sending them from server to client, clients will then create a new class with the same signature. Note: a NEW CLASS with the same signature, NOT JUST A NEW OBJECT of the original class.
Of course there are some workaround for this. You may write your own serializer (see this post on SO for an example) or your own ISerializationSurrogate.
If you can deploy/share your assemblies to your clients you have a nice workaround: just deploy them and DataContractSerializer will build the right object on your clients (exactly the same one you had on the server, with all its attributes). Just remember that:
If custom attributes comes from run-time values (for example because of localization) then they'll be resolved on the client, not on the server (because attributes will be created on the client, their values won't be included in the XML message).
In the client application you need to add a reference to the assembly that contains your types.
When you add your service reference you have to instruct VS to use them (or it'll create proxies), in the Service Reference Settings dialog select Reuse types in referenced assemblies (you can limit this to only assemblies you want to share).

WCF Xml/Json serialization of domain objects, what exactly is getting serialized?

I have a domain class User that has at least 20 properties, and it is from another library so it doesn't have any contract decorations. When I return this over a WCF service as xml or json, its only bringing back like 3 of the properties. I thought maybe it was leaving out collections and whatnot, but even simple fields like Name and Email were not being returned at all.
So I guess my question is, can someone explain what exactly is being serialized and returned over the service? None of the properties are decorated with anything like [DataMember], yet some are serialized and returned while others are not. As I understand, it should automatically serialize all public properties. And on a side thought, if someone could point me in the right direction of how to add these declarations to an existing library to assist in the serialization, it would be appreciated.
UPDATE:
I was looking at the wsdl and found the reference to an xsd file (assumingly generated by the serializer). I noticed that I only has those 3 [mapping]
fields listed. not sure what this is or if I can mess with it.
It turns out that the reason these properties weren't serializing is because they weren't exactly public in that they were read-only. I actually had the properties set to:
public string MyProperty { get; internal set; }
I did this because I do use object initializers in my internal system classes (controller type stuff) and do not wish to allow the consumer to set these properties. I read that you can set them to protected and it will allow it to serialize, however this doesn't work for my implementation.
These are POCO classes, so my solution (albeit not exactly an answer to the problem) was to create DTO classes. Since all of the properties in the DTOs were fully public, all I do is populate those with data from the POCO and return the dto. Everything gets serialized properly.
Take a look at your domain class, and see if it is inheriting from another class. If it is, the User class probably only has the three properties you are seeing.
What I have found to work well is to create a special service model (or view model) as the public data interface, not a direct interface to the domain model. As a benefit, you have much greater control of the data that can be exposed - you limit the risk of unintentional data leakage, as well as optimizing the data sent over the wire.
Best of luck!

How to use XmlAttributeOverrides with WCF

I have a WCF service using basicHttpBinding. On a service method I have a class that is returned, for this class I need to dynamically / programmatically exclude properties and change property names for the XML. This needs to be done both in the WSDL and when the service method is called.
I have searched for the best solution and it seems that I will need to (1) use the XmlAttributeOverrides with the XmlSerializer or (2) implement the IXmlSerializable on the class that needs to be customized. Or there may be a better solution altogether. I know that Property Name + "Specified" can be added to the class and then those properties can be excluded. However, this does not exclude in the WSDL and this doesn't solve the property renaming issue.
Why do I want this? Because of globalization and customization of our application. There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
After MUCH research I the best option is to swap out the WCF serializer with my own custom serializer. However, I never found good examples of how to do this for a custom class that would use the XmlSerializer. Also I'm not sure how I would pass in the XmlAttributeOverrides for a specific class.
Also, this might not be the case for others who want this same functionality but in my application I only need to initialize the values once for the lifetime of the app. Too bad C# doesn't allow static readonly variables to be used with attributes.
Here is an simple example of a class:
public Customer
{
public string Address1
{
get;
set;
}
public string Address2
{
get;
set;
}
public string Zipcode
{
get;
set;
}
}
In this example I would like to for certain installations of the application use PostalCode instead of Zipcode and hide the Address2 property.
Your help is very much appreciated.
Thanks,
Tyler
There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
A standard approach is to create a special Data Transfer Object (DTO). Or several.
I know this seems like a bit of a cop out, but since your object property names are dynamic why not just use property bagging instead of doing this XMLSerializer shuffle?

How do I stop a setter being exposed over web services?

I want to have an class like this,
public class Apple
{
public string Size { get; set;}
public string Colour { get; set;}
public string Shape { get; set;}
public int appleId { get; set;}
}
I want to expose that over web services using some web methods like this,
public void AddApple(Apple apple)
{
}
public Apple GetApple(int appleId)
{
}
So when I add a service reference in visual studio to that webservice I get client proxy objects generated for me allowing me to create an Apple on the client side and send that through to the webservice.
Is there a way for me to make one of those properties read only on the client side? I need the setters there so that I can set the values on the server side, but I want to control which data they can update on the client side.
Any ideas?
What I could do is pass in some of the data in the constructor, and only expose getters on the ones I want to be read only, but I want to use an object mapper on the server side. That means ideally I would want to leave the setters there.
In general, you cannot assume control over proxies generated at client side. So correct way would be to ignore values sent by client (or raise exception if he changes those values). The service documentation has to be explicitly mention such things.
Edit:
Yet another work-around would be to divide your data class into two classes - one non-editable by client (say Apple1) and another editable - say Apple2. So now service update method can only accept Apple2 so that client can know looking at generated proxy code what he can change. On server side, you can have Apple1 inherited from Apple2 to have complete data but I believe that proxy generated at client will/can anyway have two different unrelated classes. Perhaps better way in such case would be to have composite full AppleFull containing Apple1 and Apple2.
Please refer to the following question and its answers, I just skimmed through your question but I believe that it is a simillar problem as I faced -
WCF serialization and Value object pattern in Domain Driven Design
Another way to achieve that would be to share the assembly containing the Apple class (but no server side component) between server and client. Make the setters internal and mark the server side assemblies as friends using the InternalsVisibleTo attribute.
This will allow the server to use the setters but not the client.

Mixing custom and basic serialization?

I've got a class with well over 100 properties (it's a database mapping class) and one of the properties has to be in a method. In other words this data is not exposed via a property but via methods:
"ABCType GetABC(), SetABC(ABCType value)"
It's all very un-C#-like. I shudder when I see it.
The class needs to be serializable so it can be sent over web services, and the data exposed by the Get/Set methods needs to be serialized too. (It's in a method because of a strange thing the grid I'm using does with reflection; it can't handle objects that contain properties of the same type as the containing object. The problem property stores the original state of the database object in case a revert is required. Inefficient implementation, yes - but I'm unable to re-engineer it.)
My question is this: since only this 1 field needs custom serialization code, I'd like to use custom serialization only for calling GetABC and SetABC, reverting to basic XML serialization for the rest of the class. It'll minimize potential for bugs in my serialization code. Is there a way?
The first thing I'd try is adding a property for serialization, but hiding it from the UI:
[Browsable(false)] // hide in UI
public SomeType ABC {
get {return GetABC();}
set {SetABC(value);}
}
You can't really mix and match serialization unfortunately; once you implement IXmlSerializable, you own everything. If you were using WCF, then DataContractSerialier supports non-public properties for serialization, so you could use:
[DataMember]
private SomeType ABC {
get {return GetABC();}
set {SetABC(value);}
}
but this doesn't apply for "asmx" web-services via XmlSerializer.
Does the [Browsable] trick work at all? Assuming the custom grid uses TypeDescriptor, another option might be to hide it via ICustomTypeDescriptor, but that is a lot of work just to hide a property...

Categories

Resources