Net core dapper and postgres jsonb column - json

I want to POST some custom JSON to my postgres jsonb column via postman using the below request.
The custom part is sent in the "Settings" > "data" node. I don't want to apply the custom part to a model I just want to send in any kind of json and store it.
{
"name": "Test",
"settings": {
"data": {
"customdata": "hello",
"custommore": "bye"
}
}
}
The "data" node is modelled - like this:
public string Data { get; set; } //I have tried JSONDocument and Jsonb types to no avail.
Postman errors with this:
"errors": {
"$.settings.data": [
"The JSON value could not be converted to System.String. Path: $.settings.data | LineNumber: 3 | BytePositionInLine: 17."
]
}
The request doesn't even hit my controller method. I think it is because the customdata and custommore is not mapped to a model.
Is there a way of sending in custom JSON data that is not fixed to a model of any kind - or must it be part of a model?
I'm struggling to find anything about this that doesn't relate to EF core which is not what I am using.

You can use custom model binding,and get json data from HttpContext.Request.Body,and then use sonConvert.DeserializeObject to get json object.You can set the data to the format you want.
Here is a demo:
DataBinder:
public class DataBinder:IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var model1 = new Customer();
using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body))
{
var body = reader.ReadToEndAsync();
var mydata = JsonConvert.DeserializeObject<JObject>(body.Result);
model1.Name = mydata["name"].ToString();
model1.Settings = new Settings
{
Data = mydata["settings"]["data"].ToString()
};
}
bindingContext.Result = ModelBindingResult.Success(model1);
return Task.CompletedTask;
}
}
Controller:
public IActionResult TestCustomModelBinding([ModelBinder(BinderType = typeof(DataBinder))]Customer customer) {
return Ok();
}
result:

Related

Tornadofx REST client

I have followed an example shown here
link
And i got the hang of it, i managed to create my own "Employee" entity and i found some dummy api data online to play with.
like this Problem is, the tornadofx throws null pointer error, and i think its because the rest response sends something like this
{
"status": "success",
"data": [
{
"id": "1",
"employee_name": "Tiger Nixon",
"employee_salary": "320800",
"employee_age": "61",
"profile_image": ""
},
but when i use mocky and provide JUST the json part
[
{
"id": "1",
"employee_name": "Tiger Nixon",
"employee_salary": "320800",
"employee_age": "61",
"profile_image": ""
},...]
it all works fine.
I think those additional fields "status" and "success" in response confuse the rest client of tornadofx, and i cant manage to get it to work, is there anyway to tell client to ignore every other fields besides those of json data.
All links are functional, so you can try yourself.
full working example
package com.example.demo.view
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleStringProperty
import javafx.scene.layout.BorderPane
import tornadofx.*
import javax.json.JsonObject
class Employee (id:Int?=null , name: String? = null, age: Int?=null): JsonModel {
val idProperty = SimpleIntegerProperty(this, "id")
var id by idProperty
val ageProperty = SimpleIntegerProperty(this, "age")
var age by ageProperty
val employeeNameProperty = SimpleStringProperty(this, "name", name)
var name by employeeNameProperty
override fun updateModel(json: JsonObject) {
with(json) {
id = int("id")!!
age = int("employee_age")!!
name = string("employee_name")
}
}
override fun toJSON(json: JsonBuilder) {
with(json) {
add("id", id)
add("employee_name", name)
add("employee_age", age)
}
}
}
class PersonEditor : View("Person Editor") {
override val root = BorderPane()
val api : Rest by inject()
var persons = listOf(Employee(1,"John", 44), Employee(2,"Jay", 33)).observable()
val model = PersonModel(Employee())
init {
api.baseURI = "https://run.mocky.io/v3/"
val response = api.get("f17509ba-2d12-4c56-b441-69ab23302e43")
println(response.list())
println(response.list().toModel<Employee>()[0].name)
// print( p.get(1))
with(root) {
center {
tableview(response.list().toModel<Employee>()) {
column("Id", Employee::idProperty)
column("Name", Employee::employeeNameProperty)
column("Age", Employee::ageProperty)
// Update the person inside the view model on selection change
model.rebindOnChange(this) { selectedPerson ->
item = selectedPerson ?: Employee()
}
}
}
right {
form {
fieldset("Edit person") {
field("Id") {
textfield(model.id)
}
field("Name") {
textfield(model.name)
}
field("Age") {
textfield(model.age)
}
button("Save") {
enableWhen(model.dirty)
action {
save()
}
}
button("Reset").action {
model.rollback()
}
}
}
}
}
}
private fun save() {
// Flush changes from the text fields into the model
model.commit()
// The edited person is contained in the model
val person = model.item
// A real application would persist the person here
println("Saving ${person.employeeNameProperty} / ${person.ageProperty}")
}
}
class PersonModel(person: Employee) : ItemViewModel<Employee>(person) {
val id = bind(Employee::idProperty)
val name = bind(Employee::employeeNameProperty)
val age = bind(Employee::ageProperty)
}
if you replace base url and send request to http://dummy.restapiexample.com/api/v1/employees you will get an error that i am talking about
Your call to mocky returns a list, so .list() works fine. Your call to restapiexample, however, returns an object, not a list, so .list() won't do what you expect. You can probably use something like this, though I haven't tested it:
response.one().getJsonArray("data").toModel<Employee>()[0].name)
Further explanation:
If you're not familiar with the structure of JSON, check out the diagrams on the JSON homepage.
TornadoFX has two convenience functions for working with JSON returns: .list() and .one(). The .list() function will check if the result is a JsonArray. If so, it simply returns it. If it is instead a JsonObject, it wraps that object in a list and returns the new list.
In your case, since restapiexample is returning an object, the result of your call to .list() is a JsonArray with a single object. It looks something like this:
[
{
"status": "success",
"data": [...]
}
]
Obviously that single object cannot be converted to an Employee, so dereferencing anything off of it will result in a NullPointerException.
The .one() function on the other hand will check if the response is a JsonObject. If it is, it simply returns the object. If, however, the response is a JsonArray, it will take the first item from the array and return that item.

Angular 4 - Typescript: json2typescript json key mapper

Sorry but I didn't explain it very well. I edit my question again:
I have an angular 4 application and I use json2typescript to convert from json to object and vice versa but I have a problem because I have a class structure and the response json from an external api has another structure. Example:
Customer {
#JsonProperty('idCardNumber', String)
idCardNumber: string = undefined;
#JsonProperty('rolInfo.name',String)
name: string = undefined;
#JsonProperty('rolInfo.surname',String)
surname: string = undefined;
}
External Json API Reponse:
{
"idCardNumber": "08989765F",
"rolInfo": {
"name": "John"
"surname: "Smith"
}
}
So, I would like to map from the json above to my Customer object and not to change my structure. I tried to put 'rolInfo.name' into the JsonProperty, but that doesn't work.
Change your Customer class to something like below
Customer {
#JsonProperty('idCardNumber', String)
idCardNumber: string = undefined;
#JsonProperty('rolInfo', Any)
rolInfo: any = {}; // if you set this to undefined, handle it in getter/setter
get name(): string {
return this.rolInfo['name'];
}
set name(value: string) {
this.rolInfo['name'] = value;
}
get surname(): string {
return this.rolInfo['surname'];
}
set surname(value: string) {
this.rolInfo['surname'] = value;
}
}
That should do it
Seems like the response JSON is already in a good format and you don’t need to do the conversion.
I would recommend creating models as they allow for serialization and deserialization when making API calls and binding the response to that model.

CodeFluent JSON Serialization Does Not Work for All Fields

I'm using CodeFluent JsonUtilities to convert an object to JSON. Using anything else seems to have various other issues (e.g. Circular Referencing).
Here's some functions I use to convert to JSON for ASP.NET MVC, using CodeFluent.Runtime.Utilities namespace (for the JsonUtilities).
public static ContentResult ConvertToJsonResponse(object obj)
{
string json = JsonUtilities.Serialize(obj);
return PrepareJson(json);
}
/// <summary>
/// Converts JSON string to a ContentResult object suitable as a response back to the client
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static ContentResult PrepareJson(string json)
{
ContentResult content = new ContentResult();
content.Content = json;
content.ContentType = "application/json";
return content;
}
The problem is when I use JsonUtilities to convert an object it seems to have skipped some nested objects.
For example, I tried to convert DataSourceResult object (from Telerik) to JSON using CodeFluent.
public ActionResult UpdateTeam([DataSourceRequest]DataSourceRequest request, TeamViewModel teamViewModel)
{
ModelState.AddModelError("", "An Error!");
DataSourceResult dataSourceResult = new[] { teamViewModel }.ToDataSourceResult(request, ModelState);
ContentResult ret = CodeFluentJson.ConvertToJsonResponse(dataSourceResult);
return ret;
}
The dataSourceResult holds three main properties:
Data - which hold my Model that contains my data.
Total - which holds the amount of data objects there are.
Errors - which holds all the errors of my MVC model. It is very nested, with a lot of properties under it.
When I try to use CodeFluent utilities to convert the DataSourceResult object it works to convert "Data", and "Total" fields, but with Errors, it skips it entirely, resulting in the below JSON string:
{
"Data":[
{
"ExampleProperty":"ExampleValue"
}
],
"Total":1,
"AggregateResults":null,
"Errors":{ }
}
I'm guessing the issue is with the "Errors" object being too nested for the CodeFluent converter.
So my question is are there any CodeFluent serialization options/code I'm missing to work with heavily nested objects for JSON conversion?
The problem comes from the fact you're creating a model error with an empty key. It's not forbidden but JsonUtilities just skip dictionary values with an empty key, by design.
Just use a real key, like this:
ModelState.AddModelError("my first error", "An Error!");
ModelState.AddModelError("my second error", "An Error!");
And you'll see the errors collection serialized, like this:
{
"Data":[
{
"ExampleProperty":"ExampleValue"
}],
"Total": 1,
"AggregateResults": null,
"Errors": {
"my first error": {
"errors": [
"An Error!"
]
},
"my second error": {
"errors": [
"An Error!"
]
}
}
}
Otherwise, if you really want to keep empty keys, then you can leverage the JsonUtilitiesOptions class that has callbacks for tweaking the serialization (and deserialization) process. Careful with this as you can easily break JSON syntax. This is how you could do it, in a way that should handle all cases:
JsonUtilitiesOptions options = new JsonUtilitiesOptions();
options.WriteValueCallback += (e) =>
{
IDictionary valueDic = e.Value as IDictionary;
if (valueDic != null)
{
e.Writer.Write('{');
bool first = true;
foreach (DictionaryEntry entry in valueDic)
{
if (!first)
{
e.Writer.Write(',');
}
else
{
first = false;
}
// reuse JsonUtilities already written functions
JsonUtilities.WriteString(e.Writer, entry.Key.ToString(), e.Options);
e.Writer.Write(':');
// object graph is for cyclic/infinite serialization checks
JsonUtilities.WriteValue(e.Writer, entry.Value, e.ObjectGraph, e.Options);
}
e.Writer.Write('}');
e.Handled = true; // ok, we did it
}
};
string json = JsonUtilities.Serialize(obj, options);
Now, you'll get this result:
{
"Data":[
{
"ExampleProperty":"ExampleValue"
}],
"Total": 1,
"AggregateResults": null,
"Errors": {
"": {
"errors": [
"An Error!"
]
}
}
}

Breezejs Naming Convention withtout metadata

I've been reading answers and the Breeze documentation, digging in the code, but I just can't make this work.
I've a WebService with NancyFx that it's used by many webapps, and I decided to go for the convention of the camelCase in json.
'[{"id":"0", "slug":"my-slug","name":"Slug"}]'
And now I'm looking into breeze and I want to use oData query, I'm using Linq2Rest, so my first attempt module is like this..
private dynamic GetFoos(dynamic p)
{
//Converting the request params to NameValueCollection to be used by
//extensionmethod Filter of Linq2Rest
var nvc = this.BuildNameValueCollection();
var institutions = Repository.Get();
return Response.AsJson(institutions.Filter(nvc));
}
And this works like a charm when I do something like
http://foo.com/foos$filter=Slug%20eq%20my-slug
Ok, now let's play with Breeze....So I've my metadata by hand and I've something like this
function addFooModel() {
addType({
name: 'Foo',
dataProperties: {
id : { type : ID },
name : { nullOk: false },
slug : { nullOk: false },
}
});
};
And I query my service like this
var query = breeze.EntityQuery.from('foos')
.using(manager)
.where('slug', '==', slug)
.toType('Foo');
So this is where everything breaks, first of all since my property in .NET of my class Foo is declared like this...
public class Foo
{
public int Id {get; set;}
public string Name {get; set;}
public string Slug {get; set;}
}
So the url that is constructed by Breeze is http://foo.com/foos$filter=slug%20eq%20my-slug and since my property is in PascalCase Linq2Rest says noupe, there's no slug property.
If I declare the breeze.NamingConvention.camelCase.setAsDefault(); the url is correct but the data is not bound because it expects the json in PascalCase but the json returned is in camelcase
I've tried to create my namingConvention, setting nameOnServer on the dataProperty, create a jsonResultAdapter and I can not make it work....
I know I just can do this
var query = breeze.EntityQuery.from('foos')
.using(manager)
.where('Slug', '==', slug);
And this works but the data.results is not bound to the Foo model....
So is there a way to do this from breeze like:
Create the url in PascalCase and then resolve the json in CamelCase.
I did this workaround with jsonResultAdapter but I don't like it
var jsonResultsAdapter = new breeze.JsonResultsAdapter({
name: "fooAdapter",
extractResults: function(json) {
return json.results;
},
visitNode: function(node, mappingContext, nodeContext) {
for (var key in node){
node[key.substr(0, 1).toUpperCase() + key.substr(1)] = node[key];
}
return {
entityType: mappingContext.query.resultType
};
}
});
Suggestions....
Thanks!
EDIT.
Right now I'm using the camelCase configuration that comes with breeze breeze.NamingConvention.camelCase.setAsDefault(); the properties of my model is in camelCase and the jsonResultsAdapter I'm using is this one...
var jsonResultsAdapter = new breeze.JsonResultsAdapter({
name: "fooAdapter",
extractResults: function(json) {
return json.results;
},
visitNode: function(node, mappingContext, nodeContext) {
for (var key in node){
node[key.substr(0, 1).toUpperCase() + key.substr(1)] = node[key];
}
return {
entityType: mappingContext.query.resultType
};
}
});
I'm adding to the node the same properties but in PascalCase. If the server serves this json '[{"id":"0", "slug":"my-slug","name":"Slug"}]' after the adapter the node transforms in '[{"id":"0", "slug":"my-slug","name":"Slug", "Id":"0", "Slug":"my-slug","Name":"Slug"}]'and then I don't know where yet, Breeze maps the properties in PascalCase to camelCase because of the namingConvention that I'm using.
The query is this one
var query = breeze.EntityQuery.from('foos')
.using(manager)
.where('slug', '==', slug)
.toType('Foo');

JSON ignore fields outside data maps

I am getting some response :
var xxx_api = { "user" : {
"name":"satishpandey",
"sites":[
{
"name":"SEO Product",
"url":"http://www.xxx.com/"
} ]
}};
I want to exclude all the string those are outside json data.
var xxx_api and ; are needs to be excluded.
Is there anything in jackson to exclude these strings?
Assuming you are using this in a get/post (restful-like) method, maybe that has to do with the header of the webservice method you are using. I am using REST and I am able to specify the format I want to receive the json input like this
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
public Response myMethod(#FormParam("post") String jsonInput){
// ...
// use jsonInput
mapper.readValue(jsonInput, ...);
// ...
}
Considering this, I guess the input written to the var jsonInput (in the header) would be
{ "user" : {
"name":"satishpandey",
"sites":[
{
"name":"SEO Product",
"url":"http://www.xxx.com/"
} ]
}};
I didn't find any solutions for it in jackson. Now I am using String.substring() method for getting the desired results.
StringBuilder stringBuilder = new StringBuilder(jsonString);
stringBuilder.replace(0, stringBuilder.indexOf("{"), "");
stringBuilder.replace(stringBuilder.lastIndexOf("}") + 1, stringBuilder.length(), "");
It is working perfectly for me.