JSON property with hyphen in it in ServiceStack - json

I have some JSON formed like this:
{
"snippet-format":"raw",
"total":1,"start":1,
"page-length":200, ...
}
I have a C# DTO with members called Total, Start etc. These are successfully having the values from the above placed in to them. I don't know how to name properties for the snippet-format and page-length JSON items above though.
I've tried SnippetFormat and Snippet_Format to no avail.
Could someone please point me in the right direction.
Also, if a value happens to be a W3C xs:dateTime string, is there a type I can use that ServiceStack will automatically populate for me?
Thanks in advance.

Checked into the next version of ServiceStack.Text v3.9.43+, the Lenient property convention now supports hyphened properties, so you will be able to do:
public class Hyphens
{
public string SnippetFormat { get; set; }
public int Total { get; set; }
public int Start { get; set; }
public int PageLength { get; set; }
}
JsConfig.PropertyConvention = JsonPropertyConvention.Lenient;
var json = #"{
""snippet-format"":""raw"",
""total"":1,
""start"":1,
""page-length"":200
}";
var dto = json.FromJson<Hyphens>();
Assert.That(dto.SnippetFormat, Is.EqualTo("raw"));
Assert.That(dto.Total, Is.EqualTo(1));
Assert.That(dto.Start, Is.EqualTo(1));
Assert.That(dto.PageLength, Is.EqualTo(200));
In the meantime you will have to parse it dynamically, e.g:
var map = JsonObject.Parse(json);
Assert.That(map["snippet-format"], Is.EqualTo("raw"));
Assert.That(map["total"], Is.EqualTo("1"));
Assert.That(map["start"], Is.EqualTo("1"));
Assert.That(map["page-length"], Is.EqualTo("200"));

Related

Dealing with external namespaces for a POCO data model implemented through NJsonSchema auto-generated classes

In a dotnet microservice architecture, to avoid exposing my data model and its logic, I am willing to add a POCO data model layer following a mechanism: fullDataModel>json>pocoDataModel.
Here is my reduced fullDataModel
public class MyDto
{
public string Name { get; set; }
public AnExternalNamespace.MyExternalType ExternalObject { get; set; }
}
To implement the above mechanism, I am using NJSonSchema CSharpGenerator as follow:
// generate Json schema from ConsoleApp1
JsonSchema schema = await JsonSchema.FromFileAsync("MyDto.txt");
CSharpGeneratorSettings settings = new CSharpGeneratorSettings
{
ClassStyle = CSharpClassStyle.Poco,
Namespace = "MS1Namespace",
GenerateDataAnnotations = true
};
var generator = new CSharpGenerator(schema, settings);
var modelFile = generator.GenerateFile();
// generate the C# file in a another ConsoleApp2 for testing purpose
using (StreamWriter writer = new StreamWriter("..\\ConsoleApp2\\MyDtoFromJson.cs"))
{
writer.WriteLine(modelFile);
}
Problem, the MyDto class refers to a type which comes from an external library (AnExternalNamespace.MyExternalType). But the mechanism I implemented does not preserve this type of reference, rather it generates a type bounded to each namespace associated with each microservice I use that implement this type. Have a look at the C# generated file which is bounded to MS1Namespace
namespace MS1Namespace
{
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.8.0.0 (Newtonsoft.Json v13.0.0.0)")]
public partial class MyExternalType
{
[Newtonsoft.Json.JsonProperty("Name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Name { get; set; }
[Newtonsoft.Json.JsonProperty("Description", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Description { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.8.0.0 (Newtonsoft.Json v13.0.0.0)")]
public partial class MyDto
{
[Newtonsoft.Json.JsonProperty("Name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Name { get; set; }
[Newtonsoft.Json.JsonProperty("ExternalId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public MyExternalType ExternalObject { get; set; }
}
}
In other words, with this mechanism, MyExternalType is kind of redefined relative to each MSnNamespace for every microservice (1 to n) where it is embedded. On the contrary, I would like to be able to receive objects that refer to the type defined in the AnExternalNamespace each time I send a request to these microservices. That would allow me treat the data of same type coming from these different microservices in a unified way with the unique AnExternalNamespace.MyExternalType
I have tried to play with Json annotations in MyDto class. For example by doing this:
[JsonProperty(TypeNameHandling = TypeNameHandling.Auto)]
public MyPublicLibrary.MyExternalType ExternalId { get; set; }
This does not allow to get out of the MS1Namespace scope to which all the auto-generated classes are bounded.
So, the only solution I see to overcome this for now is to implement an explicit&implicit cast in each microservice embedding this type from MSnNamespace.MyExternalType to AnExternalNamespace.MyExternalType.
But I was thinking NJSonSchema settings could offer me a more elegant way to deal with this situation. Am I missing something here? Do you see any other options or better practice while continuing keeping passing through the Json serialization/deserialization process?
Thanks in advance for your help!

Web API - Converting JSON to Complex Object Type (DTO) with inheritance

I have the following scenario:
public class WidgetBaseDTO
{
public int WidgetID
{
get;
set;
}
}
public class WidgetTypeA : WidgetBaseDTO
{
public string SomeProperty1
{
get;
set;
}
}
public class WidgetTypeB : WidgetBaseDTO
{
public int SomeProperty2
{
get;
set;
}
}
and my web service returns the following dashboard object whereas the Widgets collection could be of either type A or B:
public class DashboardDTO
{
public List<WidgetBaseDTO> Widgets
{
get;
set;
}
}
my problem is that although the client receives correct JSON content, which is dependent on the Widget type, when reading the response content, they are all being translated to WidgetBaseDTO. what is the correct way to convert these objects to the relevant types?
this is how the response is being read:
string relativeRequestUri = string.Format("api/dashboards/GetDashboard?dashboardID={0}", dashboardID);
using (var client = new HttpClient())
{
// set client options
client.BaseAddress = this.BaseUri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// make request
HttpResponseMessage response = client.GetAsync(relativeRequestUri).Result;
if (response.IsSuccessStatusCode)
{
DashboardDTO dashboard = response.Content.ReadAsAsync<DashboardDTO>().Result;
}
I believe after receiving the response you are probably trying to cast WidgetBaseDTO to either WidgetTypeA or WidgetTypeB and you are seeing null? if yes, then you can try after making the following setting to the Json formatter on the server...make sure to make this setting on the client side's json formatter too.
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;
The above setting will cause the type information of WidgetTypeA or WidgetTypeB to be put over the wire which gives a hint to the client as to the actual type of the object being deserialized...you can try looking at the wire format of the response to get an idea...
Client side:
JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;
WidgetBaseDTO baseDTO = resp.Content.ReadAsAsync<WidgetBaseDTO>(new MediaTypeFormatter[] { jsonFormatter }).Result;

APEX ENUM Serialize to and Deserialize from JSON

I have APEX classes defined with enum properties that are to be serialized into JSON. Also, I am reading in JSON and deserializing them back to my defined classes.
To make the enum properties work with the JSON transitions, I have created another Integer property that gets the ordinal of the enum and sets the enum based on the enum's values list. See below:
Enum definitions:
public enum DataSourceType {
NA,
ArbitronSummary,
ArbitronTally,
NielsenSummary,
NielsenTally,
Scarborough,
Strata,
None
}
public enum FilterJoinType {
AndJoin,
OrJoin,
NotJoin
}
public enum HourByHourInterval {
NA0,
NA1,
Quarterly,
NA3,
Hourly
}
APEX Class definitions:
public class HourByHourRequest {
public List<String> Books { get; set; }
public DataSourceType eDataSource { get; set; }
public Integer DataSource {
get {
if (eDataSource == null)
return 0;
return eDataSource.ordinal();
}
set {
eDataSource = lib_ap.DataSourceType.values()[value];
}
}
public FilterJoinType eFilterJoinType { get; set; }
public Integer FilterJoinType {
get {
if (eFilterJoinType == null)
return 0;
return eFilterJoinType.ordinal();
}
set {
eFilterJoinType = lib_ap.FilterJoinType.values()[value];
}
}
public HourByHourInterval eInterval { get; set; }
public Integer Interval {
get {
if (eInterval == null)
return 0;
return eInterval.ordinal();
}
set {
eInterval = lib_ap.HourByHourInterval.values()[value];
}
}
}
APEX code using the class to serialize to JSON and deserialize from JSON:
HourByHourRequest request = new HourByHourRequest();
request.Books = new List<String>();
request.Books.add('BookName');
request.eDataSource = DataSourceType.ArbitronTally;
request.eFilterJoinType = FilterJoinType.AndJoin;
request.eInterval = HourByHourInterval.Hourly;
String jsonStr = JSON.serialize(request);
HourByHourRequest request2 = (HourByHourRequest)JSON.deserialize(request, HourByHourRequest.class);
The reason why I used an Integer property to go with each enum property is because upon serializing to JSON the enum value is lost. So having the corresponding Integer value retains the value in JSON, which can be deserialized back successfully... except in the code shown above. The above code will actually fail at the deserialize part due to a "Duplicate field" error for each of the enum/integer field pairs. Both the enum and integer fields are being included in the JSON string when serialized, even though only the integer field is retaining the value.
Sample JSON:
{"Interval":4,
"eInterval":{},
"FilterJoinType":0,
"eFilterJoinType":{},...
My question: Is there a way to ignore fields for serializing to JSON? That would resolve the "Duplicate field" error. Otherwise, how would I go about an appropriate way to handling enums when converting to/from JSON? Thanks!
Got an answer at https://salesforce.stackexchange.com/questions/18498/apex-enum-serialize-to-and-deserialize-from-json.
Basically, you can mark fields as transient to be ignored for serializing to JSON.

MVC3 / JSON: How do I use model binding when my property names are renamed via a DataContract?

I use a DataContractJsonSerializer to create a JsonResult for my model data when sending data to the client. My model represents data to be displayed in a data table, and I wished to change the name of the model's properties in the JSON only so that less verbose property names are sent over the wire for each data table row. Now, I'm attempting to send the data table cell values via JSON to the server's controller action method. The names of the fields being sent back are still the short names, and the model binding doesn't seem to like that. What can I do to get model binding working and preserve the ability to sent alternate property names via JSON?
Model:
[DataContract()]
public class UsageListModel {
[DataMember(Name = "results")]
public IEnumerable<UsageModel> Usages { get; set; }
}
[DataContract()]
public class UsageModel {
[DataMember(Name = "job")]
public string JobId { get; set; }
[DataMember(Name = "dt")]
public DateTime UsageDate { get; set; }
[DataMember(Name = "qty")]
public int Quantity { get; set; }
[DataMember(Name = "uom")]
public string UnitOfMeasure { get; set; }
[DataMember(Name = "nts")]
public string Notes { get; set; }
}
It's not as elegant but I usually do this by just making an intermediary class (I refer to it as a ViewModel) that has those shortname properties and can be translated back and forth between it and the actual Model. Although it seems like busy work, the ViewModel can be useful beyond this stint - for example you can use it to easily cache client-side info if the need arises, or serialize/deserialize exactly what's going to/from the client in tests.
I'm still in disbelief that MVC doesn't offer some easier method to bind using custom attributes (or even the .NET data-contract attributes). Given that it doesn't... your best bet is to implement your own IModelBinder. Use reflection to get the DataMember names of the properties, and look for those values in the binding context.
Here's a great reference on model binding: http://msdn.microsoft.com/en-us/magazine/hh781022.aspx
A good general approach to maintaining custom binders: http://lostechies.com/jimmybogard/2009/03/18/a-better-model-binder/
EDIT
Generic model binder that handles a defined type. To add this to your application, add this line in global.asax:
ModelBinders.Binders.Add(typeof(UsageModel), new CustomModelBinder<UsageModel>());
And the binder:
public class CustomModelBinder<T> : IModelBinder
{
public override bool IsMatch(Type t)
{
return t == typeof(T);
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Type t = typeof(T);
var entity = (bindingContext.Model ?? Activator.CreateInstance(t));
// Cycle through the properties and assign values.
foreach (PropertyInfo p in t.GetProperties())
{
string sourceKey;
// this is what you'd do if you wanted to bind to the property name
// string sourceKey = p.Name;
// TODO bind sourceKey to the name in attribute DataMember
Type propertyType = p.PropertyType;
// now try to get the value from the context ...
ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(sourceKey);
if (valueResult != null)
{
bindingContext.ModelState.SetModelValue(sourceKey, valueResult);
p.SetValue(entity, valueResult.ConvertTo(propertyType), null);
}
}
return entity;
}
}
I stumbled across a potential answer to this question randomly while browsing this other question.
I never realized this until now, but apparently you can add attributes to method parameters. Let's take a simple example:
public ActionResult SomeMethod(string val) {
return View(val);
}
If you call this URL -- /MyController/SomeMethod?val=mytestval -- then you'll get back "mytestval" in the model, right? So now you can write this:
public ActionResult SomeMethod([Bind(Prefix="alias")] string val) {
return View(val);
}
Now this URL will produce the same result: /MyController/SomeMethod?alias=mytestval.
Anyway, I'm still not sure if that will answer your question, but I thought it was very interesting.

WP7 ArrayAdapter equivalent

I have a JSON object returned from a WCF Service, it returns two “Article” objects and looks like this:
{"GetArticlesResult":[{"ArticleName":"Mobile Application Development","ArticleText":"Lots of text here."},{"ArticleName":"Super Fast Development Cycle","ArticleText":"Lots more text here."}]}
And I can display it in a message box with this code:
MessageBox.Show(e.Result);
What I want to do is display a list of ArticleNames in a ListBox, I will then want to link them to another page to display the ArticleText but that’s later for now.
My research has shown me that I need to use the DataContractJsonSerializer but this is where I’m stuck, all the examples seem to be a little complicated. In and Android app I would simply use an ArrayAdapter to populate something. Can I do something similar in a WP7 app?
Cheers,
Mike.
EDIT
I now have the following, how do I display the results in a ListBox?
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(e.Result));
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Article));
//put ms into a listBox here????....
[DataContract]
public class Article
{
[DataMember()]
public string Title { get; set; }
[DataMember()]
public string Text { get; set; }
}
You need to set the ItemsSource property of the listbox to an array/list (or ObservableCollection if you're going to add more items while it's displaying). If you are using a ViewModel, you can bind the ItemsSource property to an ObservableCollection property on your VM and it will update automatically.
You can use JSON.NET (it's faster than DataContractJsonSerializer) to either deserialize the JSON to a strongly typed object model and bind that or you can use the same library to deserialize the JSON to a dynamic and then access the JSON properties from that.
If you use a strongly typed object model, you'll need to implement the changes xyzzer made to Article/ArticleList in order for it to map properly.
Maybe a List would work for you to deserialize/represent an array from a JSON structure. Otherwise - the question is too vague. Are you asking how to display a collection in a ListBox? Using an ItemsSource binding...
*EDIT
Try this:
var jsonString = "{\"GetArticlesResult\":[{\"ArticleName\":\"Mobile Application Development\",\"ArticleText\":\"Lots of text here.\"},{\"ArticleName\":\"Super Fast Development Cycle\",\"ArticleText\":\"Lots more text here.\"}]}";
var articles = Deserialize<ArticleList>(jsonString);
Debug.WriteLine(articles.GetArticlesResult.Count);
[DataContract]
public class ArticleList
{
[DataMember]
public List<Article> GetArticlesResult { get; set; }
}
[DataContract]
public class Article
{
[DataMember(Name = "ArticleName")]
public string ArticleName { get; set; }
[DataMember(Name = "ArticleText")]
public string ArticleText { get; set; }
}
public static T Deserialize<T>(string strData) where T : class
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
byte[] byteArray = Encoding.UTF8.GetBytes(strData);
MemoryStream memoryStream = new MemoryStream(byteArray);
T tRet = serializer.ReadObject(memoryStream) as T;
memoryStream.Dispose();
return tRet;
}