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

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!

Related

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;

Generic Singleton and share data between pages

To share data (complexe data ) between pages in my windows phone 8 application I want to implement a singleton, but I want it to be generic, is it possible? I suppose that it creates a new instance for each type isn't it?
public sealed class NavigationContextService<T>
{
private static readonly NavigationContextService<T> instance = new NavigationContextService<T>();
private NavigationContextService()
{
}
public static NavigationContextService<T> Instance
{
get
{
return instance;
}
}
public List<T> ShareList { get; set; }
public T ShareData { get; set; }
}
It is creating a new instance for every type, because it is generic - you want it to be like this (if you start with generics, take a look at some tutorials, blogs or MSDN - you will easily find many in the internet).
It is still a singleton. When you use
NavigationContextService<string>.Instance.ShareList.Add("Text");
then you have one Instance for type string. Generics helps a lot when you want to create same methods/classes that differ in type.
On the other hand if you want to create Singleton that will hold different types then you can for example modify your class to be non Generic like this:
public sealed class NavigationContextServiceNonGeneric
{
private static readonly NavigationContextServiceNonGeneric instance = new NavigationContextServiceNonGeneric();
private NavigationContextServiceNonGeneric() { ShareList = new List<object>(); }
public static NavigationContextServiceNonGeneric Instance
{ get { return instance; } }
public List<object> ShareList { get; set; }
public object ShareData { get; set; }
}
As you can see in the code above I haven't defined the 'exact' type of shared data - it is object type. Then you can easily hold most of data with it:
NavigationContextServiceNonGeneric.Instance.ShareList.Add("Text");
NavigationContextServiceNonGeneric.Instance.ShareList.Add(3);
NavigationContextServiceNonGeneric.Instance.ShareList.Add(3.0f);
It is singleton, which can hold different types of shared data. BUT it has also disavantages - the main is that you have to remember what type of data you hold and in what order. In my opinion Generic version is better because of that fact.
Everything depends on the purpose of your code. There may be easier and better ways that those two approaches.
As for the Page Navigation, you can for example try to use a method from this article - you extend Navigation service to pass the object:
public static class Extensions
{
private static object Data;
public static void Navigate(this NavigationService navigationService, Uri source, object data)
{
Data = data;
navigationService.Navigate(source);
}
public static object GetNavigationData(this NavigationService service) { return Data; }
}
Then you use it:
NavigationService.Navigate(yourUri, DataToPass);
After Navigation you can get your data:
string myTextData = NavigationService.GetNavigationData() as string;
This method has to disadvantages: it is not type-safe and your data won't be preserved in Tombstone mode.
As for the second disadvantage you can easily use PhoneApplicationService.State Property for the purpose of Page Navigation - it is a dictionary (which is preserved while tombstoning):
PhoneApplicationService.Current.State.Add("data", yourData);
Then when you want to get your data:
yourDataType yourData = PhoneApplicationService.Current.State["data"] as yourDataType;
There are also more ways in which you can pass the data.

JSON property with hyphen in it in ServiceStack

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"));

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;
}