How to serialize a tree of objects with YamlDotNet - serialization

I have the following class:
public class MenuItem
{
public string Title { get; set; }
public List<MenuItem> Items { get; set; }
public MenuItem()
{
Items = new List<MenuItem>();
}
}
How it is possible to properly serialize this?
Adrian Tarniceru
and I created a tree of MenuItem objects and wanted to serialize it with YamlDotNet but the result was unexpected.
MenuItem _root = new MenuItem() { Title = "Menu" };
MenuItem childItem1 = new MenuItem() { Title = "Child item #1" };
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.1" });
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.2" });
_root.Items.Add(childItem1);
_root.Items.Add(new MenuItem() { Title = "Child item #2" });
var serializer = new Serializer();
string fileContent = serializer.Serialize(_root);
using (StreamWriter writer = new StreamWriter("Menu.yaml"))
{
writer.Write(fileContent);
}
result was:
...
bu I expected a tree of MenuItems in Yaml.

Related

Blazor binding parent/child dropdown controls fails to set default value on child control

On a parent/child dropdown scenario, I'm trying to display a default value for the child dropdown each time the parent dropdown is updated.
The code does the job, since it updates the sample label, but the child dropdown does not display anything.
For simplicity I am demonstrating the issue with a country/zone pair of select controls.
Initial render correctly shows the default country and the default zone of the country.
Updating the country sets the new default zone on the label but the zones select turns blank:
#page "/test"
<select #bind="#CountryName">
#foreach (var country in Countries)
{
<option>#country.Name</option>
}
</select>
<select #bind="#ZoneName">
#foreach (string zone in Zones)
{
<option>#zone</option>
}
</select>
<div>Selected country: #CountryName</div>
<div>Selected zone: #ZoneName</div>
#code {
private List<Country> Countries;
private List<String> Zones = new();
private string countryName;
private string CountryName
{
get => countryName;
set
{
countryName = value;
var country = Countries.First(x => x.Name == value);
Zones = country.Zones.Select(x => x.Name).ToList();
ZoneName = country.DefaultZoneName;
}
}
private string zoneName;
private string ZoneName
{
get => zoneName;
set
{
zoneName = value;
}
}
protected override void OnInitialized()
{
//data factory
var barcelona = new Zone() { Name = "Barcelona" };
var madrid = new Zone() { Name = "Madrid" };
var spain = new Country() { Name = "Spain" };
spain.Zones.Add(barcelona);
spain.Zones.Add(madrid);
spain.DefaultZoneName = spain.Zones.Last().Name;;
var açores = new Zone() { Name = "Açores" };
var algarve = new Zone() { Name = "Algarve" };
var portugal = new Country() { Name = "Portugal" };
portugal.Zones.Add(açores);
portugal.Zones.Add(algarve);
portugal.DefaultZoneName = portugal.Zones.Last().Name;
Countries = new List<Country>();
Countries.Add(spain);
Countries.Add(portugal);
CountryName = Countries.Last().Name;
base.OnInitialized();
}
//models
public class Country
{
public string Name { get; set; }
public List<Zone> Zones { get; set; } = new();
public string DefaultZoneName { get; set; }
}
public class Zone
{
public string Name { get; set; }
}
}
The problem is that set method on variable doesn't cause the page to re-render: automatic re-render occurs with a Task handling an #event, and forced re-render occurs with StateHasChanged.
You are trying to use set method because 2-way binding on the select consumes the #onchange event, so you have no way to do anything when a value is selected. However, this is a trap. Blazor allows C# boolean for selected (and also for other things like disabled or hidden).
You already took some time to set up your data nicely, so you can track selection by reference, not by copying the string values of names to new variables.
I think the following is an improvement. I hope it helps you, as this same situation will come up very often in Blazor:
#page "/"
<select #onchange="(args) => SelectedCountry = Countries.First(x => x.Name==args.Value?.ToString())">
#foreach (var country in Countries)
{
<option selected="#(country == SelectedCountry)" >#country.Name</option>
}
</select>
<select #onchange="(args) => SelectedCountry.SelectedZone = SelectedCountry.Zones.First(x => x.Name==args.Value?.ToString())">
#foreach (var zone in SelectedCountry.Zones)
{
<option selected="#(zone == SelectedCountry.SelectedZone)">#zone.Name</option>
}
</select>
<div>Selected country: #SelectedCountry.Name</div>
<div>Selected zone: #SelectedCountry?.SelectedZone?.Name</div>
#code {
private List<Country> Countries = new();
private Country SelectedCountry = new();
protected override void OnInitialized()
{
//data factory
var barcelona = new Zone() { Name = "Barcelona" };
var madrid = new Zone() { Name = "Madrid" };
var spain = new Country() { Name = "Spain" };
spain.Zones.Add(barcelona);
spain.Zones.Add(madrid);
spain.SelectedZone = spain.Zones.Last();
var açores = new Zone() { Name = "Açores" };
var algarve = new Zone() { Name = "Algarve" };
var portugal = new Country() { Name = "Portugal" };
portugal.Zones.Add(açores);
portugal.Zones.Add(algarve);
portugal.SelectedZone = portugal.Zones.Last();
Countries = new List<Country>();
Countries.Add(spain);
Countries.Add(portugal);
SelectedCountry = portugal;
}
//models
public class Country
{
public string Name { get; set; }
public List<Zone> Zones { get; set; } = new();
public Zone? SelectedZone;
}
public class Zone
{
public string Name { get; set; }
}
}

Data not binding to listbox in mvc4

I have listbox
#Html.ListBox("lais", new SelectList(Model.lista, "Value", "Text"), new {#class = "mylistbox"});
Here am getting list data but not binding to listbox (list items value )
This is my action method
public ActionResult PrintRFIDTag()
{
Print p =new Print();
p.lista = GetList();
return View(p);
}
public SelectList GetList()
{
System.Management.ManagementScope objMS =
new System.Management.ManagementScope(ManagementPath.DefaultPath);
objMS.Connect();
List<SelectListItem> items = new List<SelectListItem>();
SelectQuery objQuery = new SelectQuery("SELECT * FROM Win32_Printer");
ManagementObjectSearcher objMOS = new ManagementObjectSearcher(objMS, objQuery);
System.Management.ManagementObjectCollection objMOC = objMOS.Get();
foreach (ManagementObject Printers in objMOC)
{
if (Convert.ToBoolean(Printers["Network"])) // ALL NETWORK PRINTERS.
{
var emptyItem = new SelectListItem()
{
Value = Printers["Name"].ToString(),
Text = "00"
};
items.Add(emptyItem);
}
}
SelectList objselectlist = new SelectList(items,"Value");
return objselectlist;
}
}
Here is my model class
public class Print
{
public SelectList lista { get; set; }
public string Name { get; set; }
}
Returning from view but not binding to listbox
Your help will be appropriated
try this:
#Html.ListBoxFor(m=>m.lista ,Model.lista) and change line SelectList objselectlist = new SelectList(items,"Value"); to this: SelectList objselectlist = new SelectList(items,"Value","Text");

RavenDB static index on dictionary

I have an application that uses documents, that contain list of attributes in a dictionary, for some reason we need to use a static index and query/filter over these attributes.
A prototype looks like this:
class Program
{
static void Main(string[] args)
{
IDocumentStore store = new DocumentStore() { DefaultDatabase = "Test", Url = "http://localhost:8081" };
store.Initialize();
IndexCreation.CreateIndexes(typeof(Program).Assembly, store);
using (var session = store.OpenSession())
{
session.Store(new Document { Id = "1", Name = "doc_name", Attributes = new Dictionary<string, object> { { "Type", "1" }, { "Status", "Active" } } });
session.SaveChanges();
}
using (var session = store.OpenSession())
{
// works
var l1 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Type"] == "1").ToList();
// not working
var l2 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Status"] == "Active").ToList();
}
}
}
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
a.Attributes,
Attributes_Type = a.Attributes["Type"]
});
}
}
[Serializable]
public class Document
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, object> Attributes { get; set; }
}
But since I need to query using any arbitrary Attribute name/value this index does solve our problem. Actually the list of attributes is known at run-time (so we tried modifying the Map expression to inject any number of attribute names, but so far we weren't successful). Is there a way how to define the index in some dynamic fashion?
You need to write it like:
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
_ = a.Attributes.Select(x=>CreateField("Attributes_"+x.Key, x.Value),
});
}
}

Serializing object graph using MongoDB Bson serializer

I've been playing a little with the MongoDB Bson serializer, using the following piece of code:
class Program
{
public class myValue
{
public int Id = 0;
public string Label = "";
}
public class myValueMap : Dictionary<string, myValue>
{
}
public class myProdData
{
public myValueMap Mapping { get; set; }
}
public class mySystemPosition
{
public string Text { get; set; }
public myProdData ProdData { get; set; }
}
static void Main(string[] args)
{
BsonClassMap.RegisterClassMap<mySystemPosition>();
BsonClassMap.RegisterClassMap<myProdData>();
BsonClassMap.RegisterClassMap<myValueMap>();
BsonClassMap.RegisterClassMap<myValue>();
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new myValueMap()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var bson = o.ToBson();
var text = Encoding.ASCII.GetString(bson);
}
}
however I don't seem to be able to get the myProdData.Mapping serialized....
Do I need to configure the MongoDB Bson serializer in a special way, to make this work?
You no need to use BsonClassMap.RegisterClassMap if you no need custom serializtion(documentation).
All your classes will be desirialzied according to default rules.
Also i am changed your example a little bit to get it work(i've replaces myValueMap class with Dictionary):
public class myProdData
{
public Dictionary<string, myValue> Mapping { get; set; }
}
static void Main(string[] args)
{
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new Dictionary<string, myValue>()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var json = o.ToJson();
Console.WriteLine(json);
Console.ReadKey();
}
Here is console output(just well formatted):
{
"Text":null,
"ProdData":{
"Mapping":{
"123":{
"_id":1,
"Label":"Item1"
},
"345":{
"_id":2,
"Label":"Item2"
}
}
}
}
You can test your serializtion using ToJson() extention method, in order to view that all correct and after that use ToBson() if need.
The problem is that myValueMap derives from Dictionary. That results in a class that the AutoMap method can't handle.
I recommend you just use the Dictionary directly, as Andrew did in his reply.
Ufortunately the myValueMap is an object that I can't easily change, however it turns out, that's pretty easy to create your own (de)serializer....
public class myValueMapSerializer : IBsonSerializer
{
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, System.Type actualType, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var res = new myValueMap();
var ser = new DictionarySerializer<string, myValue>();
var dic = (Dictionary<string, myValue>)ser.Deserialize(bsonReader, typeof(Dictionary<string, myValue>), options);
foreach (var item in dic)
{
res.Add(item.Key, item.Value);
}
return res;
}
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, IBsonSerializationOptions options)
{
throw new Exception("Not implemented");
}
public bool GetDocumentId(object document, out object id, out IIdGenerator idGenerator)
{
id = null;
idGenerator = null;
return false;
}
public void Serialize(Bson.IO.BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var ser = new DictionarySerializer<string, myValue>();
ser.Serialize(bsonWriter, typeof(DictionarySerializer<string, myValue>), value, options);
}
public void SetDocumentId(object document, object id)
{
return;
}
}

How do I test "Parameters Passed In Final Call" using RhinoMocks?

What's the best way in Rhino Mocks to test that a particular parameter is passed on the FINAL call to a method? Eg mockview.SetSomething(myObj) might be called any number of times by mockview.Init, but I want to test that the last time it's called as mockview.SetSomething(inParticular).
Now I know I can use GetArgumentsForCallsMadeOn with this, but my problem is that it doesn't work if I've subsequently changed the parameter holding variable. e.g
public interface IView
{
void SetSomething(ViewData data);
}
public class ViewData
{
public int Age { get; set; }
public string Name { get; set; }
public ViewData Person(int age, string name)
{
Age = age;
Name = name;
return (this);
}
}
public class WorkingPresenter
{
public void Init(IView view)
{
var data = new ViewData {Age = 1, Name = "One"};
view.SetSomething(data);
data = new ViewData {Age = 2, Name = "Two"};
view.SetSomething(data);
data = new ViewData {Age = 3, Name = "Three"};
}
}
public class NotWorkingPresenter
{
private ViewData _data;
public void Init(IView view)
{
_data = new ViewData();
view.SetSomething(_data.Person(1, "One"));
view.SetSomething(_data.Person(2, "Two"));
_data.Person(3, "Three");
}
}
then my tests are ...
[Test]
public void GetDataOfLastCall()
{
ViewData dummydata=null;
var view = MockRepository.GenerateStub<IView>();
//Approach 1 : This works
var workingPresenter = new WorkingPresenter();
workingPresenter.Init(view);
var lastCall = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata)).Count - 1;
var lastParams = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata))[lastCall];
var lastData = (ViewData)lastParams[0];
//Approach 2: This doesn't
var notWorkingPresenter = new NotWorkingPresenter();
notWorkingPresenter.Init(view);
lastCall = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata)).Count - 1;
lastParams = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata))[lastCall];
lastData = (ViewData)lastParams[0];
What I want is to verify that the last call to SetSomething was with {name="Two", age=2}. Now workingPresenter does this but wouldn't you expect notWorkingPresenter to do so too?
There must be something else going on in your code (outside of the mocking). I just threw together a few items:
public interface IView
{
void SetSomething(ViewData data);
}
public class ViewData
{
public int Age { get; set; }
public string Name { get; set; }
}
And I tested it with:
[TestMethod]
public void GetDataOfLastCall()
{
var view = MockRepository.GenerateStub<IView>();
var data = new ViewData {Age = 1, Name = "One"};
view.SetSomething(data);
data = new ViewData { Age = 2, Name = "Two" };
view.SetSomething(data);
data = new ViewData { Age = 3, Name = "Three" };
var lastCall = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(data)).Count - 1;
var lastParams = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(data))[lastCall];
var lastData = (ViewData) lastParams[0];
}
And I got the values of 2 and "Two" inside the ViewData. It appears Rhino.Mocks supports what you want to do. Could you create a failing test case that shows the issue identified in your original question (where you got a reference to the most recent information)?