Returning a Json-field from SQL to ASP.NET Core API - json

I'm building a relatively simple Get-method in an ASP.NET Core (3+) application. (Currently 3.1 - to be migrated to 5)
The object I need to return looks like this:
public class Data
{
public int ID { get;set;}
public string Name { get;set;}
public string Settings { get; set;}
}
And the Get-method is simply this:
public IActionResult<Data> GetData()
{
var data = _dbContext.GetData<Data>();
return Ok(data);
}
This works perfectly - except for one thing.
In SQL - the settings column (varchar(8000)), contains JSON data. In some cases, a setting can be something simple like : { "threshold": 8754 } and sometimes it can be a large complex object with many fields, but it is always valid Json.
On the ASP side, it does exactly what you would expect. It turns a serialized Json object that contains an INT and 2 x strings.
I would like for it to return an INT, ONE String and One Json Object.
Is there any way that I can tell the serializer that the Settings-property contains Json?
In a perfect world, I would love something like this:
public class Data
{
public int ID { get;set;}
public string Name { get;set;}
[SerializeContentAsJson]
public string Settings { get; set;}
}
Is there a way to do this or is there some other fairly elegant solution to this problem?
Btw. I fully realize that the caller can specify the content types that he/she will accept. In this case, the API is purely for use inside my team and we will always want JSON, so I can compromise on this being a relatively custom solution that might not work if you wanted text/html or some other content type.

Related

ASP .Net core web api serialization issue for property names with underscore

The simplest version of the problem is shown by creating a new ASP .NET core web api project. Adding this class
public class TestClass
{
public string AAAA_BBBB { get; set; } = "1";
}
And this controller method
[HttpGet("GetTestClass")]
public TestClass GetTestClass()
{
return new TestClass();
}
results in this response
{
"aaaA_BBBB": "1"
}
After experimenting, it looks like anything which has an underscore in it is treated this way. All the characters in the bit before the FIRST underscore except for the last character in that set get converted into lower case.
So
AAAA_BBBB becomes aaaA_BBBB
AAAAAAAA_BBB_CCC_DDD becomes aaaaaaaA_BBB_CCC_DDD
A_BBB becomes a_BBBB
AA_BB becomes aA_BB
Why is this happening and how do I fix it?
By default Web API serializes the fields of types that have a [Serializable] attribute (e.g. Version).That's what the Web API guys wanted.
You can decorate with a property name like so:
[JsonPropertyName("AAAA_BBBB")]
public string AAAA_BBBB { get; set; } = "1";
Or,you can refer to these two links:Link1 and Link2 to stop Web API doing it in JSON.
Update
The same effect can be achieved using the following code in Startup:
services.AddControllersWithViews().
AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

Converting simple value to JSON in ASP.NET Core API

Sometimes my ASP.NET Core API needs to return a simple value i.e. bool, int or string even though in most cases, I return complex objects/arrays as JSON.
I think for consistency purposes, it's a good idea to return even simple values as JSON. What's the easiest way to convert a simple value, whether it's bool or int into JSON?
My standard controller action looks like this -- see below -- which gives me the ability to return status codes as well as data. Therefore, I'd like to stick to that approach, rather than return JsonResult.
public async Task<IActionResult> Get()
{
// Some logic
return Ok(data);
}
I'm just trying to figure out the easiest way to convert my data into JSON, if it's not already in JSON format.
Looking at your code, I assume your application is supposed to be a service that needs to return some kind of data serialised in JSON.
Well, good news is ASP.NET Core already includes a data serialiser that would do the job for you.
You may need to set it up according to your needs.
For example, let's assume the following data class:
public class Data {
public string Name { get; }
public string Value { get; }
public bool IsValid { get; }
public Data(string name, string value, bool isValid) {
Name = name;
Value = value;
IsValid = isValid;
}
}
Then the following method in your Controller:
public async Task<IActionResult> Get() {
var data = new Data("sample name", "this is a value", true);
return Ok(data);
}
would return:
{
"name": "sample name",
"value": "this is a value",
"isValid": true
}
Even thought the standard serialisation behaviour may fit fine for very simple implementations, you may need more control on how your different data types should be serialised (and deserialised) by your application, especially when those do not exactly match the way you want to present the data back to the client. In this case you may want to use Custom Converters.
You can configure that when setting up MVC in the ConfigureServices(IServiceCollection services) method:
// Add framework services.
services.AddMvc().AddJsonOptions(jo => {
// sample serialiser setup
jo.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jo.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
jo.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
// custom Converters
jo.SerializerSettings.Converters.Add(new MyCustomConverter());
});
Here you can read and learn more on how to setup and use Custom Converters.

Anonymous object blob in database not serializing as JSON when queried

I have a need to store an unknown data structure in a SQL Server database table field via ORMLite. This is to support a timeline feature on a website where each step on the timeline contains different information, and I want to store them as generic "Steps", with the variable data in a "StepData" property. I have the POCO set up like this:
public class ItemStep
{
public ItemStep()
{
this.Complete = false;
}
[Alias("ItemStepId")]
public Guid Id { get; set; }
[References(typeof(Item))]
public Guid ItemId { get; set; }
[References(typeof(Step))]
public int StepId { get; set; }
public object StepData { get; set; }
[Reference]
public Step Step { get; set; }
public bool Complete { get; set; }
public DateTime? CompletedOn { get; set; }
}
My front-end send a JSON object for StepData, and it's saved to the database appropriately.
{itemAmount:1000,isRed:False,isBlue:True,conversion:True}
Now, when I go to retrieve that data using...
List<ItemStep> itemSteps = Db.Select<ItemStep>(q => q.ItemId == request.ItemId).OrderByDescending(q => q.StepId).ToList<ItemStep>();
...the "StepData" node of the JSON response on the client is not a Javascript Array object as I'm expecting. So, on the client (AngularJS app using Coffeescript),
ItemStep.getItemSteps(ItemId).then((response) ->
$scope.StepData = response.data.itemSteps[0].stepData
is a double-quoted string of the JSON array.
"{itemAmount:1000,isRed:False,isBlue:True,conversion:True}"
Can anybody help me with this? I've tried parsing that string as JSON and I can't seem to get it to work:
JSON.parse($scope.StepData)
I'm using the exact same methodology in other areas of the app to store and retrieve things like addresses, with the only difference I can see being that there is a specified Address class.
Thanks!
Found this link that solved my problem: https://github.com/ServiceStackV3/mythz_blog/blob/master/pages/314.md
Essentially I added a "Type" field to the ItemStep class, and set that when I create a new row (create the next step in the timeline). Then, when I retrieve that record, I call a method like "GetBody" in the referenced link (GetStepData for me), that deserializes the object using the stored Type. I then stuff that back into a generic "object" type in the return POCO so that I can include many steps of varying types in the same call. Works great!
Thanks Mythz for the blog post!

Want to design a REST API but I have too much parameter to send , is it okay to replace them with one JSON?

I am designing a REST API one of my resources is all about to getting some basic data from user side.
Here are two points that I needs to mention:
all the user's information needs to send to server side with only one http request
the user's information is about 30 different fields.
So I think having a long list of argument in server side can not be that much good and I want to replace this part with a single argument which is accepting a JSON.
Do you think is it correct to do that?
Yes. You will want to change the method to a POST instead of a GET and in the request body send the JSON formatted data.
Example using C# syntax:
Assume you have a method that returns an object called ObjectList and in order to generate the list you the constructor requires an ObjectListRequest object -
public ObjectList GetObjectList(ObjectListRequest request)
{
return new ObjectList(request)
}
Your ObjectListRequest class could contain various different parameters that the request would use -
public class ObjectListRequest
{
public string SearchText { get; set; }
public string CreatedBy { get; set; }
public int SequenceStartRange { get; set; }
public int SequenceEndRange { get; set; }
public bool HasMetaData { get; set; }
}
Now to call this method using a POST with JSON in the body you would send the following
Method: POST
Url: http://your.service.com/GetObjectList
Headers:
Content-Type: application/json
Body:
{
"request":{
"SearchText":"test text",
"CreatedBy":"myusername",
"SequenceStartRange":0,
"SequenceEndRange":15,
"HasMetaData":"true"
}
}
This is a specific example which assumes you are using C# and built in Serialization libraries from microsoft, but if not, you can still use the same basic idea to do what you are trying to do.

Share Json data between Asp.Net MVC 2 and Asp.Net server side C# code?

I created and love my Asp.Net MVC2 application. It's a very nice DDD app with Domain Model classes, View Model classes, a repository, and Json action methods to expose data.
My coworker wants to share my data with his Asp.Net Forms based C# code. He wants to pull through the Internet a class definition (like a Data Contract), then fill it with my Json results, effectively using something like a remote repository.
Any links or ideas on how to provide him with data contracts and data?
Darin Dimitrov had an excellent idea of consuming JSON data using data contracts here. Just wondering if it's possible to use MVC as the source for these items, then let him create the objects on his side, filled with data from my side.
The key to this question is how to send him my data classes, then send him my data.
class Program
{
[DataContract]
class Person
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "surname")]
public string Surname { get; set; }
[DataMember(Name="age")]
public int Age { get; set; }
}
static void Main(string[] args)
{
var json = #"{""name"" : ""michael"", ""surname"" : ""brown"", ""age"" : ""35""}";
var serializer = new DataContractJsonSerializer(typeof(Person));
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
var person = (Person)serializer.ReadObject(stream);
Console.WriteLine("Name : {0}, Surname : {1}, Age : {2}",
person.Name, person.Surname, person.Age);
}
}
}
Write an OData service. The format is JSON, but the tools to consume it easily -- from many languages -- are already written for you.
The nice thing about this is that your data is now not only consumable by your JS and your friend's ASP.NET app, it's consumable by Excel, PHP, etc.