JsonPatch to preserve naming of properties (camel-cased) - c#

I am using Microsoft.AspNetCore.JsonPatch which I've added via NuGet from here and got stuck when trying to match my properties back on API-side.
Is there any way to preserve the camel-case naming of my properties when serializing/deserializing.
My simplified object:
public class MyObject
{
public string MyCamelCaseProperty { get; set; }
}
When creating a JsonPatchDocument<MyObject> with the operation Replace I get the path /mycamelcaseproperty. But, on API-side I want to make some sort of switch-case by the path property (without the leading '/') like
var normalizedPath = operation.path.Replace("/", string.Empty)
switch(normalizedPath)
{
case nameof(MyObject.MyCamelCaseProperty):
// do replacement of the MyCamelCaseProperty property
break;
}
The question is: Can the camel-case be preserved or do I have to find another way on how to match the property-names I have to do actions on?
Any ideas would be greatly appreciated.

Related

C# Newtonsoft JSON Very simple just not sure on name of thing i need

I have read a JSON document into a hashtable and started for each loop through the Dinnersets inside of it.
I have stored the current DinnerSet in my Helper class and now I just need to use a string named CurrentMeal which simply contains a mealname and use it something like this:
String MealID = MyHelper.DinnerSet.Value.Meals.CurrentMeal.MealID
My problem is I don't know how to substitute the String CurrentMeal into this and have the whole thing expanded to return me the mealID, If I do this manually:
String MealID = MyHelper.DinnerSet.Value.Meals.Pasta.MealID
I get back the correct MealID, I am sure it is very simple I just don't know what I should be googling to get onto the right track with this
Any help greatly appreciated
EDIT: JSON Structure example:
"DinnerSet001":
"Version": "0.1",
"Enabled" : true,
"Description": "These are delicious meals for one",
"Notes": "May contain Gluten or Nuts",
"Meals": {
"Pasta": {
"MealID": "MID001",
"Description": "Basic Pasta dish in a tomato and basil sauce",
"Type": "Vegetarian"
},
The way I am reading this JSON into an object is:
dynamic DinnerSetsHash = JsonConvert.DeserializeObject<Dictionary<String, dynamic>>(jsonContent);
I then start reading the Dinnersets inside the JSON using:
foreach (var DinnerSet in DinnerSetsHash) {
I get CurrentMeal from elsewhere but i know it contains the mealnames i need such as "Pasta" and i am then hoping i should then be able to substitute it and get the MealID i need
String MealID = MyHelper.DinnerSet.Value.Meals.CurrentMeal.MealID
Regards
K.
Based on the information you've given, I think what you're looking for is the square bracket syntax, also called "indexer syntax". For example:
string CurrentMeal = "Pasta";
...
string MealID = DinnerSet.Value.Meals[CurrentMeal].MealID;
Fiddle: https://dotnetfiddle.net/bEqNFN
I agree with #dbc's comment that you would probably be better off using a strongly typed model rather than dynamic so that you get the benefits of Intellisense and compile-time type checking.
The following model should work based on the JSON you've given:
public class DinnerSet
{
public string Version { get; set; }
public bool Enabled { get; set; }
public string Description { get; set; }
public string Notes { get; set; }
public Dictionary<string, Meal> Meals { get; set; }
}
public class Meal
{
public string MealID { get; set; }
public string Description { get; set; }
public string Type { get; set; }
}
You can then deserialize into a Dictionary<string, DinnerSet> (instead of Dictionary<string, dynamic>) and your code should still work with only minimal changes.
Fiddle: https://dotnetfiddle.net/D0T98K
thank you for the input,
I was thinking this over last night and i think the question i needed to ask all along was how do i deal with a JSON file that is dynamic (as mine is), it could have any number of Dinnersets and they can contain any number of meals.
I did originally go down the strongly typed route using the paste special -> paste JSON as classes in visual studio but that didn't work for me for reasons i forget now.
I will do some testing with "indexer Syntax" thank you for the name of it! it has been driving me crazy :)
I also thought of a another way to represent what i am trying to do, I know for example in PowerShell I could have done this:
MealID = (DinnerSet.Value.Meals$(CurrentMeal)`.MealID)
and that would expand the entire right hand side and give me the value i am looking for. If there is an equivalent in C# that would also solve this for me.
EDIT: yes the indexer syntax works as the $() does in PowerShell, thanks :)
Other than that i will test with the indexer syntax and Mark your reply as the answer for now, this gives me plenty to play around with, thank you all!

Getting the right class by attribute based on string value

public ActionResult AddComplianceForm(string TemplateName)
{
}
In this ASP.net MVC5 application there is a folder Templates that contains a bunch of different classes that all have different TemplateName attributes. The first part of this method needs to find the class that has a TemplateName matching the string passed in. I then need to create an instance of whatever template matched. I am very new to working with attributes in C# so help would be very appreciated. I mostly need to know how to access that folder of classes in the program to look into it.
What you are trying to do is called "Reflection" in C#.
Below is the link to another answer that shows how to get all the classes in a namespace (I'm assuming that the physical folder implies the use of a unique namespace for the classes contained in the folder.)
Link to StackOverflow answer
**Btw you should look up reflection performance and see if it makes sense in your case. You may want to use a factory pattern instead.
This will work:
public class HomeController : Controller
{
public ActionResult AddComplianceForm(string TemplateName)
{
Assembly assembly = Assembly.Load("Testy20161006"); //assembly name
Type t = assembly.GetType("Testy20161006.Templates." + TemplateName); //namespace + class name
Object obj = (Object)Activator.CreateInstance(t);
return View();
}
Don't just use reflection
The typical way someone would deal with this is with Reflection and run-time type discovery/binding. However, this is probably a poor starting point in this exact situation. The template name is passed in as an action argument, presumably through binding to a value in the request string, and you don't want c# code that will instantiate whatever class is passed in from the web!!! That would be a serious security issue known as an insecure direct object reference.
Create a list
To mitigate the risk, the proper approach is to check the argument against a whitelist. Well, if we have a white list already, we may as well associate each item in the list with a lambda expression that returns the object you want.
class MyController
{
static private readonly Dictionary<string,Func<BaseTemplate>> _templateList = new Dictionary<string,Func<BaseTemplate>>();
static MyController()
{
_templateList.Add("ATemplate", () => return new ATemplate());
_templateList.Add("SomeOtherTemplate", () => return new SomeOtherTemplate());
_templateList.Add("JustOneMore", () => return new JustOneMore());
}
public ActionResult AddComplianceForm(string TemplateName)
{
BaseTemplate template;
try
{
template = _templateList[TemplateName]();
}
catch (KeyNotFoundException exception)
{
RedirectToAction("MyController", "InvalidTemplateError");
}
DoSomethingWithTemplate(template);
}
}
Create the list using Reflection
But what if you have a crap ton of templates? You don't want to hard code all those dictionary entries, right?
Well, you could tag each of the templates with a custom attribute, e.g. [TemplateAttribute], and then populate the list this way:
foreach (Assembly b in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type t in b.GetTypes())
{
var a = Attribute.GetCustomAttribute(t, typeof(TemplateAttribute));
if (a != null)
{
var localType = t; //Avoid closure on loop variable
_templateList.Add(t.Name, () => Activator.CreateInstance(localType) as BaseTemplate);
}
}
}
This will automatically iterate through all the types that are loaded for your application and find the ones with the TemplateAttribute. Only those types will be allowed in the action argument.
Notes:
In these examples I assume all of your templates inherit from a BaseTemplate, but if they have no ancestor in common (not recommended) I guess you could just use object.
In these examples, I store the list and implement the code in the controller, but if you are going for well-structured code you should consider moving all that stuff into some sort of factory class and just pass the string in from the controller.

DotLiquid, some beginner questions/observations

I'm investigating using dotliquid to replace a home grown piece of templating code and I'm wondering about the best way to achieve my goal.
The old code used to use sigils in the template and, together with a Dictionary, used regexes to search and replace. So you did something like this in the template file:
Specific error: {#ErrorId#}
Error description: {#Description#}
Additional information:{#AdditionalInformation#}
And in the C# code:
Dictionary<string, string> tokensAndValues = new Dictionary<string, string>
{
{#"ErrorId", errorId},
{#"Description", description},
{#"AdditionalInformation", additionalInformation}
};
I came across dotnetliquid and it appears quite powerful (possibly overkill for my needs?). I've got it working but I want to ask if I'm going about this in the correct fashion?
It appears I'm forced to declare a class viz.
public class EmailTemplateInfo : Drop
{
public string ErrorId { get; set; }
public string Description { get; set; }
public string AdditionalInformation { get; set; }
}
And then use that as follows:
Template.NamingConvention = new CSharpNamingConvention();
Template template = Template.Parse(templateText);
EmailTemplateInfo emailTemplateInfo = new EmailTemplateInfo
{
AdditionalInformation = additionalInformation,
Description = description,
ErrorId = errorId
};
string htmlText = template.Render(Hash.FromAnonymousObject(new {emailTemplateInfo = emailTemplateInfo }));
A few questions:
Is this the correct way to do this? If it is then I'll propose doing an addition to the docs that demonstrates this functionality.
Secondly in the template that I use do I need to qualify the placeholders with the name of the variable like this?
Specific error: {{emailTemplateInfo.ErrorId}}
Error description: {{emailTemplateInfo.Description}}
Additional information:{{emailTemplateInfo.AdditionalInformation}}
I can't see how the naming convention declaration [Template.NamingConvention = new CSharpNamingConvention();] ties in with the template variable declaration below it. Is there some sort of global caching going on?
Yes, inheriting from Drop is one way to do it. The other mechanism that DotLiquid provides is Template.RegisterSimpleType(...) - see the unit tests for examples.
Yes, you do need to qualify property names with the name of the variable, as in your example. The alternative would be to create a Hash containing top-level keys for AdditionalInformation, Description, ErrorId, and pass that to template.Render(...). You can do that using Hash.FromDictionary(...), as shown here.
The naming convention doesn't have a connection to the variable declaration. The naming convention is only used when resolving property names. For example, if you used RubyNamingConvention, then you'd need to write {{ emailTemplateInfo.additional_information }} in your template.

Converting JSON data into an object

I am very new to this.Pardon me if I make any mistakes.
I have data in JSON form.Can I read this data directly and use it in C# code ?
From what I understood from reading up on the internet,I think I have to convert it into an object form to use the data.Am I right ?
If yes,Then I saw this method to convert as below :
string data = JsonConvert.DeserializeObject<string>(getmyissue());
getmyissue is the function which returns a string which has data in json format.
This gives me an exception saying
"Error reading string.Unexpected Token."
Can someone guide me where am I going wrong ?
EDIT
MyIssue.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example
{
public class MyIssue
{
public string name{get;set;}
public string description { get; set; }
public string created { get;set; }
public string updated{get;set;}
public string displayName { get; set; }
}
}
Program.cs
MyIssue obj=null;
try
{
obj = JsonConvert.DeserializeObject<MyIssue>(manager.getmyissue());
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Name: "+obj.name);
The easiest way to de-serialize Json in a C#/.NET program is to use the brilliant NewtonSoft JSON library.
There are numerous ways to do it, but I have to admit that the NS libs just get on with the task (and no I'm not a member of the team etc, just an Avid User :-) ).
To do what you want for example, if you had:
{'Name': 'A person', 'AllowAccess': true,'Areas': ['Sales','Admin']}
You would first build an object to represent it as follows:
public MyObject
{
public string Name { get; set; }
public bool AllowAccess { get; set; }
public List<string> Areas { get; set; }
}
Once you've done this, it's a simple case of just doing the following:
string jsonString = "// Your json formated string data goes here";
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(jsonString);
The properties in your object should at that point, reflect the properties in the JSON data you sent to it.
You will of course need to add the NS JSON Libs to your project, either via NuGet or Manually, which ever is easier for you, everything you need to know about that is here:
How to install JSON.NET using NuGet?
The really good thing about NS JSON however is not the ease of use, but the fact that it can also do dynamic de-serialization.
This comes in handy if you've no idea what to expect in the JSON you receive, and so don't know ahead of time how to construct an object to hold the results.
Rather than repeat what others have said however, you can find more information of doing things dynamically in this stack overflow post:
Deserializing JSON using JSon.NET with dynamic data
Update
Looking at your JSON data you have way more fields/properties in there than your trying to parse, and none of the libraries in common use (To the best of my knowledge) will pick and choose the fields to copy, you either have an object that represents them all, or not at all, the later of which I believe is the problem your facing.
I have a rather neat "JSON" plug in for chrome, than when given a chunk of JSON data formats the output for me nicely and makes it easy to read, it also helps massively when defining objects, allowing you to see the full nested structure of your data, here are a series of images showing your JSON data formatted using this plugin:
I'm not going to paste anymore images in, but that goes on for another 4 pages!!
Now, some extra information that may help you.
I know from experience (I had to write a parser in PHP for these Jira webhooks) that within the Jira control panel, you can configure your webhooks to ONLY return the information your interested in.
Right now, it looks like you've just told the system to dump everything, for every event that you've hooked too (Which looks like - all of them), it's been a while since I did any work with these, but as well as a global webhook, you also have individual webhooks, which only fire on specific events and produce JSON data that's very much smaller than what your dealing with here.
I'd therefore advise you, to take a look in your Jira control panel (Or ask your Admin/Lead Dev/etc to take a look) and seriously trim down as much of that data as you can.
Further more, if memory serves me right, you can also make various web API calls to the Jira service to get this info too, and in that case you can tell the API exactly what your interested in, meaning it will only return the fields you need.
Right now, your main problem is the sheer volume of data your trying to deal with, if you tackle that problem, you'll find the issues surrounding the code your trying to get working will be very much easier to deal with.
Update 2
Just to make it clearer what I mean by using a "dynamic" type to get at your data, you would use something like the following code:
string jsonString = "// Your json formated string data goes here";
var result = JsonConvert.DeserializeObject<dynamic>(jsonString);
The difference here is that your using the C# dynamic type rather than a strongly typed object of your own design.
"dynamic" is useful, because it's kind of like having an empty object, and then having the properties added for you, without you having to define it.
What this essentially means is that, if you pass in the following JSON:
{'Name': 'A person', 'AllowAccess': true,'Areas': ['Sales','Admin']}
You'll end up with a dynamic object that looks like:
result = dynamic
{
public string Name { get; set; }
public bool AllowAccess { get; set; }
public List<string> Areas { get; set; }
}
thus:
result.Name
will get you access to the contents of the Name field and so on.
If your JSON was then changed to become:
{'Name': 'A person', 'AllowAccess': true,'Areas': ['Sales','Admin'], 'Location': 'The World' }
Your object would magically have a property called 'Location' containing the value 'The World' which you could access using:
result.Location
In your case, this would allow you to define your concrete object EG:
public MyObject
{
public string Name { get; set; }
public string Email { get; set; }
}
and then do something like the following (Assuming that your inbound JSON had properties in called Name & Email):
string jsonString = "// Your json formated string data goes here";
var result = JsonConvert.DeserializeObject<dynamic>(jsonString);
MyObject myObject = new MyObject
{
Name = result.Name,
Email = result.Email
}
You'd then discard the dynamic object as you'd not need it anymore.
The BIG problem your going to have with this approach is maintaining your models. Manual property assignment is all fine and dandy for a small handful of properties and objects, but it soon becomes a huge maintenance nightmare as your software grows.
I'm sure it doesn't take much to imagine what kind of task you'd be facing if you had to do this for 100 different JSON requests and 50 different types of objects.
For this reason, using this approach you should really consider using some kind of mapping technology such as "AutoMapper", however for now I'm going to advise you leave that until later before you start researching it, as it'll not help you to be clear about dealing with this dynamic approach.
The JSON you get is already a string, so converting it to string doesn't make much sense. You need to create classes that reflect the structure represented by the JSON string.
For example to convert the following JSON into objects, you'd have to create a class for the users:
{"user":{"name":"asdf","teamname":"b","email":"c","players":["1","2"]}}
public class User
{
public string name { get; set; }
public string teamname { get; set; }
public string email { get; set; }
public Array players { get; set; }
}
Then you should be able to use this:
JavaScriptSerializer jss= new JavaScriptSerializer();
List<User> users = jss.Deserialize<List<User>>(jsonResponse);

Obfuscation with JSON.net

I am using Json.Net for serialization and unserialization on a class. When I try to obsfucate the class in an assembly, I will not be able to unserialize the JSON string correctly. I have try using JsonProperty Attribute but it still not able to unserialize correctly.
Does anyone know how to get around this other than setting the class not to obsfucate?
Thanks in advance.
Updates:
I have created a simple class for JSON object as below:
public class JsonTestClass
{
[JsonProperty("JsonID")]
public int Id { get; set; }
[JsonProperty("JsonName")]
public string Name { get; set; }
[JsonProperty("JsonYesNo")]
public bool YesNo { get; set; }
}
And the code to serialize JsonTestClass objects into Json string is:
//Serialize
var jsonObj = new JsonTestClass()
{
Id = 1,
Name = "John",
YesNo = true,
};
var JsonStr = JsonConvert.SerializeObject(jsonObj);
Trace.WriteLine(">>" + JsonStr);
And unserialize Json string to JsonTestClass is as follow:
//Unserialize
var JsonStr = "{\"JsonID\":1,\"JsonName\":\"John Abc\",\"JsonYesNo\":true}";
Trace.WriteLine("<<" + JsonStr);
var jsonObj = JsonConvert.DeserializeObject<JsonTestClass>(JsonStr);
if (jsonObj == null)
{
Trace.WriteLine("-- JsonObj is null");
}
else
{
Trace.WriteLine(string.Format("-- Id={0} Name={1} YesNo={2}", jsonObj.Id, jsonObj.Name, jsonObj.YesNo));
}
Everything works fine unobsfucated and the debug output for serialization is:
[64200] >>{"JsonID":1,"JsonName":"John Abc","JsonYesNo":true}
And debug output for deserialization is:
[64200] <<{"JsonID":1,"JsonName":"John Abc","JsonYesNo":true}
[64200] -- Id=1 Name=John Abc YesNo=True
After the assembly has been obsfucated (using SmartAssembly to obsfucate this) and using dotPeek to see the obsfucated assembly, the only one which somewhat resemble the JsonTestClass are:
namespace
{
internal class
{
}
}
The debug output for serialization is:
[65956] >>{}
The debug output for deserialization is:
[65956] <<{"JsonID":1,"JsonName":"John Abc","JsonYesNo":true}
[65956] -- Id=0 Name= YesNo=False
Hope this helps to clear things up.
If you are using Dotfuscator which is shipped as Community Edition with Visual Studio 15 and Visual Studio 17, you have to exclude the property names of the object you serialize from renaming. You do this in the Dotfuscator renaming tab.
After that you can serialize and deserialize like normal.
You find a detailed description here in the support corner of the Preemtive Solutions web site.
There are a couple of options, depending on your preference as to maintainability, security, etc.
Excluding properties from obfuscation
If it's just the type names that you're concerned about being obfuscated and not the property names, then you can decorate each property that is to be serialized with the Obfuscation attribute. (Here is the link for Dotfuscator's support for this attribute.) Basically, by excluding the property from renaming, this will allow Json.NET to easily identify the properties to set.
[Obfuscation(Exclude=true, Feature="renaming")]
public int MyProperty { get; set; }
Pros: Easy and straightforward
Cons: You lose some security by not
obfuscating your property names.
Expose the private backing field for deserialization
Another way to get Json.NET to deserialize an obfuscated class is to change the target of the deserialization from the public property to the private field using the JsonProperty attribute, e.g.
[JsonProperty("a")]
private int _myField;
[JsonIgnore]
public int MyProperty
{
get => _myField;
set => _myField = value;
}
NOTE: If you use "MyProperty" or nameof(MyProperty) in the JsonProperty attribute, then depending on your obfuscation settings it's very possible that it will be compiled into the .dll as "MyProperty", thus reducing the overall security that you were trying to achieve with obfuscation in the first place.
NOTE 2: This solution will most likely not work when working with the MVVM design pattern. When using this pattern, a common coding practice is to utilize the property setter to raise the INotifyPropertyChanged event. However, using the JsonProperty and JsonIgnore attributes will cause Json.NET to set the value directly on the private field using reflection instead of the via the property setter. Therefore the change event will not be raised, making this a poor solution in this particular scenario.
Pros: You can maintain full obfuscation of your property names.
Cons: You need to create backing fields for every obfuscated property that you want to participate in serialization/deserialization. Also, may break the INotifyPropertyChanged functionality when using with the MVVM pattern, depending on your implementation details.

Categories

Resources