Json-glib serialize a boolean with value false when using gobject_serialize - vala

I'm trying to serialize the class below:
public class Person : GLib.Object {
public string name { get; set; }
public int age { get; set; }
public bool alive { get; set; }
public Person (string name, int age, bool alive = true) {
Object (
name: name,
age: age,
alive: alive
);
}
}
public int main () {
var person = new Person ("mike", 33, false);
var node = Json.gobject_serialize (person);
string obj = Json.to_string (node, true);
print (obj+"\n");
return 0;
}
While i expect the output be...
{
"name": "mike",
"age": 32,
"alive": false
}
I'm getting...
{
"name": "mike",
"age": 32
}
How do i get the Boolean serialized even if the value is false?

The default serialization function of json-glib doesn't serialize a property if it contains its default value. For boolean properties, this is false, unless explicitly specified otherwise.
To make sure that serialization does happen in this case, you should explicitly implement the Serializable.serialize_property() method yourself.

Related

DocumentDB LINQ Query - Select method not supported

The Application:
.Net Standard Class Library (Containing a series of Repositories)
Latest version https://www.nuget.org/packages/Microsoft.Azure.DocumentDB.Core
Azure Cosmos DB Emulator
Sample Document Structure:
{
"ProfileName": "User Profile 123",
"Country": "UK",
"Tags": [{
"Id": "686e4c9c-f1ab-40ce-8472-cc5d63597263",
"Name": "Tag 1"
},
{
"Id": "caa2c2a0-cc5b-42e3-9943-dcda776bdc20",
"Name": "Tag 2"
}],
"Topics": [{
"Id": "baa2c2a0-cc5b-42e3-9943-dcda776bdc20",
"Name": "Topic A"
},
{
"Id": "aaa2c2a0-cc5b-42e3-9943-dcda776bdc30",
"Name": "Topic B"
},
{
"Id": "eaa2c2a0-cc5b-42e3-9943-dcda776bdc40",
"Name": "Topic C"
}]
}
The Problem:
The issue I have is that any LINQ query I execute that contains a .Select, returns an error stating that the Select method is not supported.
What I Need?
I want to be able to use a LINQ Expression to return all documents WHERE:
Country = UK
Tags contains a specific GUID
Topics contain a specific GUID
What I Need? I want to be able to use a LINQ Expression to return all documents
In your case, the Tags and Topic are object array, if you use the following linq code it will get null.
var q = from d in client.CreateDocumentQuery<Profile>(
UriFactory.CreateDocumentCollectionUri("database", "coll"))
where d.Country == "UK" && d.Tags.Contains(new Tag
{
Id = "686e4c9c-f1ab-40ce-8472-cc5d63597264"
}) && d.Topics.Contains(new Topic
{
Id = "baa2c2a0-cc5b-42e3-9943-dcda776bdc22"
})
select d;
I also try to override IEqualityComparer for Tag and Topic
public class CompareTag: IEqualityComparer<Tag>
{
public bool Equals(Tag x, Tag y)
{
return x != null && x.Id.Equals(y?.Id);
}
public int GetHashCode(Tag obj)
{
throw new NotImplementedException();
}
}
And try it again then get Contains is not supported by Azure documentDb SDK
var q = from d in client.CreateDocumentQuery<Profile>(
UriFactory.CreateDocumentCollectionUri("database", "coll"))
where d.Country == "UK" && d.Tags.Contains(new Tag
{
Id = "686e4c9c-f1ab-40ce-8472-cc5d63597264"
},new CompareTag()) && d.Topics.Contains(new Topic
{
Id = "baa2c2a0-cc5b-42e3-9943-dcda776bdc22"
}, new CompareTopic())
select d;
My workaround is that we could use the SQL query directly. It works correctly on my side. We also could test it on the Azure portal.
SELECT * FROM root WHERE (ARRAY_CONTAINS(root.Tags, {"Id": "686e4c9c-f1ab-40ce-8472-cc5d63597263"}, true) And ARRAY_CONTAINS(root.Topics, {"Id": "baa2c2a0-cc5b-42e3-9943-dcda776bdc20"}, true) And root.Country = 'UK' )
Query with SDK
FeedOptions queryOptions = new FeedOptions { MaxItemCount = -1 };
var endpointUrl = "https://cosmosaccountName.documents.azure.com:443/";
var primaryKey = "VNMIT4ydeC.....";
var client = new DocumentClient(new Uri(endpointUrl), primaryKey);
var sql = "SELECT * FROM root WHERE (ARRAY_CONTAINS(root.Tags, {\"Id\":\"686e4c9c-f1ab-40ce-8472-cc5d63597263\"},true) AND ARRAY_CONTAINS(root.Topics, {\"Id\":\"baa2c2a0-cc5b-42e3-9943-dcda776bdc20\"},true) AND root.Country = \"UK\")";
var profileQuery = client.CreateDocumentQuery<Profile>(
UriFactory.CreateDocumentCollectionUri("dbname", "collectionName"),sql, queryOptions).AsDocumentQuery();
var profileList = new List<Profile>();
while (profileQuery.HasMoreResults)
{
profileList.AddRange(profileQuery.ExecuteNextAsync<Profile>().Result);
}
Profile.cs file
public class Profile
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
public string Country { get; set; }
public string ProfileName { get; set; }
public Tag[] Tags{ get; set; }
public Topic[] Topics { get; set; }
}
Topic.cs
public class Topic
{
public string Id { get; set; }
public string Name { get; set; }
}
Tag.cs
public class Tag
{
public string Id { get; set; }
public string Name { get; set; }
}

convert DateTime type to long when serializing to json

i have a class say something like this :
public class Product {
public int Id { get; set; }
public string Name{ get; set; }
public DateTime CreatedDate{ get; set; }
public DateTime UpdatedDate{ get; set }
}
and want to convert all DateTime types to long when serializing to json , with this method :
private long convertDateToLong(DateTime datetime)
{
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long ms = (long)(datetime - epoch).TotalMilliseconds;
return ms;
}
how can i do this in asp.net web api 2 ?
edit :
i have written this code but it doesn't affect the output :
class DateTimeSerializer : BufferedMediaTypeFormatter
{
public DateTimeSerializer()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
}
public override bool CanReadType(Type type)
{
return false;
}
public override bool CanWriteType(Type type)
{
if (type == typeof (DateTime))
return true;
else
return false;
}
public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
using (var writer = new StreamWriter(writeStream))
{
var datetime = (DateTime )value ;
if (datetime != null)
{
writer.Write(convertDateToLong(datetime));
}
}
}
private long convertDateToLong(DateTime datetime)
{
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long ms = (long)(datetime - epoch).TotalMilliseconds;
return ms;
}
}
registering:
config.Formatters.Add(new DateTimeSerializer());
edit 2 :
current json :
{ "Id" : 1 , "Name" : "Sample Product" , "CreatedDate" : "2017-02-23T18:37:18.4218582+03:30" , "UpdatedDate" : "2017-02-23T18:37:18.4218582+03:30"}
expected json :
{ "Id" : 1 , "Name" : "Sample Product" , "CreatedDate" : 432309482358723 , "UpdatedDate" : 432309482358723}

In MVC can I return the json data to the view which formate like a two-dimensional array?

In the view I want to get the json data like this:
[{"name":"NewWork",
"data":[{"\/Date(1398787200000)\/",196},
{"\/Date(1398009600000)\/",62},
{"\/Date(1397836800000)\/",65}]
},
{"name":"BeiJing",
"data":[{"\/Date(1398787200000)\/",106},
{"\/Date(1398700800000)\/",100},
{"\/Date(1398441600000)\/",61},
{"\/Date(1398355200000)\/",86}]
}]
So in the controller I define the class like these,and return List<ViewModelCityData> but the return data format is not what I want.How can I change the controller ViewModelCityData?And the other question,in the view my json data need to be order by X,if I sort them in the controller,why do they not order in the view?I have to sort them again in the view.
public class ViewModelCityData
{
public string name { get; set; }
public List<Point> data { get; set; }
}
public class Point
{
public DateTime X { get; set; }
public int Y { get; set; }
}
[{"name":"NewWork",
"data":[{"X":"\/Date(1398787200000)\/","Y":196},
{"X":"\/Date(1398009600000)\/","Y":62},
{"X":"\/Date(1397836800000)\/","Y":65}]
},
{"name":"BeiJing",
"data":[{"X":"\/Date(1398787200000)\/","Y":106},
{"X":"\/Date(1398700800000)\/","Y":100},
{"X":"\/Date(1398441600000)\/","Y":61},
{"X":"\/Date(1398355200000)\/","Y":86}]}]
Solution 1
If you can live with {Key:Value} format than you can accomplish this by implementing a custom converter.
public class PointsConverter : JsonConverter
{
private DateTime _epoch = new DateTime(1970, 1, 1);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var point = (Point) value;
writer.WriteStartObject();
writer.WritePropertyName(string.Format("/Date({0})/", GetMilliseconds(point.X)));
writer.WriteRawValue(point.Y.ToString());
writer.WriteEnd();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof (Point);
}
private double GetMilliseconds(DateTime date)
{
var timeSpan = new TimeSpan(date.ToUniversalTime().Ticks - _epoch.Ticks);
return timeSpan.TotalMilliseconds;
}
}
and pass it to converter:
var serializeObject = JsonConvert.SerializeObject(models, Formatting.Indented, new PointsConverter());
Result:
[{"name": "Tiraspol",
"data": [{"/Date(1401188096166,27)/": 10},
{"/Date(1401191696166,27)/": 20}]
},
{"name": "Limassol",
"data": [{"/Date(1401195296166,27)/": 10},
{"/Date(1401198896166,27)/": 20}]
}
]
Solution 2
if you can live with [X,Y] format (instead of {X,Y}), than you can write them as an array. For this scenario use next code in converter:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var point = (Point) value;
writer.WriteStartArray();
writer.WriteValue(string.Format("/Date({0})/", GetMilliseconds(point.X)));
writer.WriteValue(point.Y.ToString());
writer.WriteEnd();
}
Result:
[{"name": "Tiraspol",
"data": [["/Date(1401188096166,27)/": 10],
["/Date(1401191696166,27)/": 20]]
},
{"name": "Limassol",
"data": [["/Date(1401195296166,27)/": 10},
["/Date(1401198896166,27)/": 20]]
}
]
Solution 3
Pass X,Y as elements of array.
var jsonReady = models.Select(x => new
{
x.name,
data = x.data.Select(point => new object[] {point.X, point.Y}).ToArray()
});
var serializeObject = JsonConvert.SerializeObject(jsonReady, Formatting.Indented, new JavaScriptDateTimeConverter());
You will get the same result as in solution 2. Not pretty nice solution but you got the concept.
Instead of this:
public List<Point> data { get; set; }
Try this:
public Dictionary<DateTime, int> data { get; set; }
And the other question,in the view my json data need to be order by X,if I sort them in the controller,why do they not order in the view?I have to sort them again in the view.
You're not showing the sort code you use, but I find it likely that you're not actually changing the list. People often do this:
list.OrderBy(e => e.X);
... when they should do this:
list = list.OrderBy(e => e.X);
If Dictionary<DateTime, int> do not work,try to use int[][]
Instead of this:
public List<Point> data { get; set; }
Try this:
public int[][] data { get; set; }

uCommerce - add dynamic property to order line

I have hit a problem building a uCommerce site based on top of the demo razor store available http://thesitedoctor.co.uk/portfolio/avenue-clothingcom/
The demo uses servicestack and the ucommerceapi for its basket functions.
I am trying to add a dynamic property to the basket (on an order line) at the point where the user clicks buy. I traced through the productpage.js file and amended the code to add a new property ('message'):
function (data) {
var variant = data.Variant;
$.uCommerce.addToBasket(
{
sku: variant.Sku,
variantSku: variant.VariantSku,
quantity: qty,
message: $('#personalisedMessage').val()
},
function () {
updateCartTotals(addToCartButton);
}
);
});
using firebug, i checked the data that is being posted
addToExistingLine: true
message: "this is a message"
quantity:"1"
sku: "Product (options: none)"
variantSku:""
Posting this does not cause an error, but I cannot tell if it has worked either - I cannot find it in the database, assuming that it would be stored in OrderProperty table. In this scenario, I am 'buying' a product with no variations.
Any help is greatly appreciated with this.
Out of the box you can't add order/line item properties via the API like that. The API payload that you've added to is specified although valid JSON won't get interpreted/used by the API.
Instead what you'll need to do is add your own method to the API. To do this you'll need to implement a service from IUCommerceApiService and then you can do what you need. I've created an example (untested) below and will get it added to the demo store as I think it's a useful bit of functionality to have.
public class AddOrderLineProperty
{
public int? OrderLineId { get; set; }
public string Sku { get; set; }
public string VariantSku { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
public class AddOrderLinePropertyResponse : IHasResponseStatus
{
public AddOrderLinePropertyResponse() { }
public AddOrderLinePropertyResponse(UCommerce.EntitiesV2.OrderLine line)
{
if (line == null)
{
UpdatedLine = new LineItem();
return;
}
var currency = SiteContext.Current.CatalogContext.CurrentCatalog.PriceGroup.Currency;
var lineTotal = new Money(line.Total.Value, currency);
UpdatedLine = new LineItem()
{
OrderLineId = line.OrderLineId,
Quantity = line.Quantity,
Sku = line.Sku,
VariantSku = line.VariantSku,
Price = line.Price,
ProductName = line.ProductName,
Total = line.Total,
FormattedTotal = lineTotal.ToString(),
UnitDiscount = line.UnitDiscount,
VAT = line.VAT,
VATRate = line.VATRate
};
}
public ResponseStatus ResponseStatus { get; set; }
public LineItem UpdatedLine { get; set; }
}
public class AddOrderLinePropertyService : ServiceBase<AddOrderLineProperty>, IUCommerceApiService
{
protected override object Run(AddOrderLineProperty request)
{
var orderLineId = request.OrderLineId;
var sku = request.Sku;
var variantSku = request.VariantSku;
var orderLine = findOrderLine(orderLineId, sku, variantSku);
addPropertyToOrderLine(orderLine, request.Key, request.Value);
TransactionLibrary.ExecuteBasketPipeline();
var newLine = findOrderLine(orderLineId, sku, variantSku);
return new AddOrderLinePropertyResponse(newLine);
}
private void addPropertyToOrderLine(OrderLine orderLine, string key, string value)
{
if (orderLine == null)
return;
orderLine[key] = value;
orderLine.Save();
}
private static OrderLine findOrderLine(int? orderLineId, string sku, string variantSku)
{
return orderLineId.HasValue
? getOrderLineByOrderLineId(orderLineId)
: getOrderLineBySku(sku, variantSku);
}
private static OrderLine getOrderLineBySku(string sku, string variantSku)
{
return String.IsNullOrWhiteSpace(variantSku)
? getOrderLines().FirstOrDefault(l => (l.Sku == sku))
: getOrderLines().FirstOrDefault(l => (l.Sku == sku && l.VariantSku == variantSku));
}
private static OrderLine getOrderLineByOrderLineId(int? orderLineId)
{
return getOrderLines().FirstOrDefault(l => l.OrderLineId == orderLineId);
}
private static ICollection<OrderLine> getOrderLines()
{
return TransactionLibrary.GetBasket().PurchaseOrder.OrderLines;
}
}
You'll need to add the new method to uCommerce.jQuery.js as well something like this:
addOrderLineProperty: function (options, onSuccess, onError) {
var defaults = {
orderLineId: 0
};
var extendedOptions = $.extend(defaults, options);
callServiceStack({ AddOrderLineProperty: extendedOptions }, onSuccess, onError);
}
Let me know if you have any issues using it.
Tim

A circular reference was detected while serializing an object of type?

DB MetersTree TABLE
id text parentId state
0 root 0 open
1 level 1 1 open
2 level 1 1 open
...
CONTROLLER
public ActionResult GetDemoTree()
{
OsosPlus2DbEntities entity = new OsosPlus2DbEntities();
MetersTree meterTree = entity.MetersTree.FirstOrDefault();
return Json(meterTree, JsonRequestBehavior.AllowGet);
}
DATA FORMAT THAT SHOULD BE (for example)
[{
"id": 1,
"text": "Node 1",
"state": "closed",
"children": [{
"id": 11,
"text": "Node 11"
},{
"id": 12,
"text": "Node 12"
}]
},{
"id": 2,
"text": "Node 2",
"state": "closed"
}]
How can I create tree Json Data? If I write MetersTree with its relationships I get the error that is defined in the title.
You need to break the circular reference that is being picked up because of the navigational property in your EF class.
You can map the results into an anonymous type like this, although this is untested:
public ActionResult GetDemoTree()
{
OsosPlus2DbEntities entity = new OsosPlus2DbEntities();
MetersTree meterTree = entity.MetersTree.FirstOrDefault();
var result = from x in meterTree
select new
{
x.id,
x.text,
x.state,
children = x.children.Select({
c => new {
c.id,
c.text
})
};
return Json(result, JsonRequestBehavior.AllowGet);
}
I solved it like this:
VIEW MODEL
public class MetersTreeViewModel
{
public int id { get; set; }
public string text { get; set; }
public string state { get; set; }
public bool #checked { get; set; }
public string attributes { get; set; }
public List<MetersTreeViewModel> children { get; set; }
}
CONTROLLER
public ActionResult GetMetersTree()
{
MetersTree meterTreeFromDb = entity.MetersTree.SingleOrDefault(x => x.sno == 5); //in my db this is the root.
List<MetersTreeViewModel> metersTreeToView = buildTree(meterTreeFromDb.Children).ToList();
return Json(metersTreeToView, JsonRequestBehavior.AllowGet);
}
BuildTree Method
private List<MetersTreeViewModel> BuildTree(IEnumerable<MetersTree> treeFromDb)
{
List<MetersTreeViewModel> metersTreeNodes = new List<MetersTreeViewModel>();
foreach (var node in treeFromDb)
{
if (node.Children.Any())
{
metersTreeNodes.Add(new MetersTreeViewModel
{
id = node.sno,
text = node.Text,
state = node.Text,
children = BuildTree(node.Children)
});
}
else {
metersTreeNodes.Add(new MetersTreeViewModel
{
id = node.sno,
text = node.Text,
state = node.Text
});
}
}
return metersTreeNodes;
}
Thanks to all who are interested in ...

Resources