Reputation: 3372
I have WCF service that return Json.
Data contract defined below
[DataContract]
public class OptionData
{
[DataMember]
public string Book { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
public string DealId { get; set; }
[DataMember]
public string DeliveryDate { get; set; }
[DataMember]
public string ExpiryDate { get; set; }
}
And Operation Contract defined as follows
[Description("Returns List of Options by user id")]
[WebGet(UriTemplate = "{sessionId}/Application/{applicationId}?start={start}&limit={limit}&page={page}", ResponseFormat = WebMessageFormat.Json)]
public List<OptionData> GetAllTask(string sessionId, string applicationId)
I need to add dynamically new DataMember field to the OptionData class .
What is the best practice to do it ?
Upvotes: 4
Views: 8167
Reputation: 8431
I just ran up against this exact issue as i posted recently here: Configuring WCF data contract for proper JSON response
My solution was to use ExpandoObject. However, I had to use Newtsoft.json to do the JSON serialization then I had to make my webservice return raw text (rather than rely on the WCF serialization). I would be happy to post my code if you like. There may be a way to do dynamic datacontracts, but I wasn't able to figure that out. But my solution does the job.
Upvotes: 1
Reputation: 31651
If you know you want JSON, you could always control the serialization yourself (see this post) - just return a string of JSON using an existing library.
Another option is to just us IsRequired = false
if you know all the possible field names.
The final alternative is to use the same pattern WCF uses for Forward-Compatible Contracts - just attach all unknown properties to single collection object (ExtensionData
). ExtensionData
is just a dictionary of key/value pairs according to this post. Unfortunately - ExtensionData
is not writable directly. This would be my approach to simulate what IExtensibleDataObject
is doing...
[DataContract]
public class OptionData
{
[DataMember]
public string Book { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
public string DealId { get; set; }
[DataMember]
public string DeliveryDate { get; set; }
[DataMember]
public string ExpiryDate { get; set; }
[DataMember]
public Dictionary<string, string> Metadata { get; set;}
}
Upvotes: 1
Reputation: 12680
As long as the client receiving the json knows how to handle dynamically added class members, you can use the Expando object strategy outlined in the accepted answer to this SO question. It uses the ServiceStack library but you may be able extract the necessary code to do what you want. A simple key/value pair approach from an ExpandoObject is documented in this code snippet.
EDIT: I should point out that this approach wouldn't rely on WCF so it may not be what you need given the context of the question.
Upvotes: 2
Reputation: 3301
If you need to dynamically control the data structures your RESTful service is returning, I think your only option is to return something like an XDocument. Your service operation could create an XDocument of an arbitrary structure and return that. That being said, I'm not sure what would happen when WCF tries to serialize an XDocument to JSON.
Upvotes: 0
Reputation: 6588
I don't think this is possible.
Let's think about what your DataContract is for a moment: it's how your service defines what it knows about - either as input or output. A client has to either find this out through meta-data exchange discovery or from a static proxy class (in a dll probably) that you provide.
If you change your contract on the fly, there's no mechanism for your service to let its clients know that the contract has changed. There's just no way to change that contract on the fly.
Even if you changed the definition of the class on the fly, including the proper attributes, etc, the client would not be able to find out about it since the contract had already previously been published.
I can't imagine what kind of mechanism would be needed to communicate changes like this on the fly with a client.
The only workaround I can think of is to have a parameter that takes in a string and allows clients to pass in XML or similar which could be just about anything. That's a pretty nasty hack though...
Upvotes: 1