String Enum in C# for creating a JSON - c#

I have a Blazor component for creating graphs with ChartJs. Based on the models, C# creates a Json for the Chart configuration. Some configurations have defined values that I can use: for example, the PointStyle accepts only few values such as circle and cross.
For this reason, I want to have the constraint to select only the accepted values for this configuration. Then, in my project I created a class PointStyle to have a sort of enum with string.
public class PointStyle
{
private PointStyle(string value) { Value = value; }
public string Value { get; private set; }
public static PointStyle Circle { get { return new PointStyle("circle"); } }
public static PointStyle Cross { get { return new PointStyle("cross"); } }
}
To obtain the correct Json configuration, in the main model I created 2 properties: PointStyle and PointStyleString.
[JsonIgnore]
public PointStyle? PointStyle {
get => _pointStyle;
set
{
_pointStyle = value;
PointStyleString = _pointStyle.Value;
}
}
private PointStyle? _pointStyle;
[JsonPropertyName("pointStyle")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? PointStyleString { get; set; }
PointStyle accepts only the values in the defined list but this is ignored from the Json converter. For example, I can configure this like
PointStyle = PointStyle.Cross
Then, the public variable PointStyleString contains the string I have to serialize in the Json and this is updated when the PointStyle sets a new value.
Now, I have to read the property Value from the class PointStyle that contains the string I have to pass to the configuration. For this reason, I have a private variable _pointStyle that saves the value for PointStyle; so, when a new value is set, I also set the PointStyleString.
When the configuration is ready, I pass through JSRuntime the configuration like
await JSRuntime.InvokeVoidAsync("setup", Config.CanvasId, dotnet_ref, Config);
I don't know exactly how the Config is translated to the Json but the resulted Json is correct for the graph.
Everything I described above is working but it seems to me quite complicated for just setting a value. Do you think I can simplify this code?

Related

Default value for a collection using Options pattern - default value always stays there

I am building a simple .NET app, and I'm using the Options pattern. My options class is simple:
public class MyOptions
{
public IEnumerable<string> Data { get; set; } = new string[0];
}
As you can see, by default, I just want the Data property to be an empty collection.
I noticed that Data ALWAYS is an empty array, even if I actually supply some non-default configuration for this property.
I also saw that Data gets properly set from my config, if I change the MyOptions class to:
public class MyOptions
{
public IEnumerable<string> Data { get; set; }
}
Why is it that my config is ignored when the default value is provided? How do I keep some default, but with an ability to change it via my config?
As discussed in comment, you need to define the property as
public class MyOptions
{
public IEnumerable<string> Data { get; set; } = = new List<string>();
}
The code new string[0] is only initializing collection with 0 capacity only.

Create a JSON object using properties of a C# class

I'm trying to construct a request body for a REST api call, and I need to create a JSON object with the list of properties I want to get back.
For eg: I have this C# object that I want to get back:
public class SomeProperties
{
public string TicketNumber { get; set; }
public Driver Driver { get; set; }
}
public class Driver
{
public string Name { get; set; }
}
To get this back, I need to put these properties in a JSON request body like this:
"properties": [
"ticketNumber",
"driver.name"
]
My attempt looks like this:
private string FetchProperties()
{
var fetchProperties = new
{
properties = new List<string>
{
"ticketNumber",
"driver.name"
}
};
var jsonResult = JsonConvert.SerializeObject(fetchProperties, Formatting.None);
return jsonResult;
}
But I don't want to hard code the properties like that.
So is there any way I can use property names from the object I want, to put in the list of strings that I made in the method above?
Thank You!
If I understand correctly,you need Metadata of model.
if you use EntityFramework, you can get metadata of your model
from this Code
and call BuildJsonMetadata() function
and if you use other mapper, I dont see any exist tool for generate metadata of model and you must generate it handly
somthing like this
First of, if you serialize the class you have (SomeProperties), you will not get driver.name. Instead you will get a string like this one that shows driver as an object,
{
properties : {
"ticketNumber" : "stringvalue",
"driver" : {
"name" : "stringValue"
}
}
}
That said, if you are interested in getting a json like this,
"properties": [
"ticketNumber",
"driver.name"
]
you will need a class (very simple one at that) that contains only a list of strings. properties is not an array of objects, but simply strings. From the looks of the FetchProperties method, you are creating an object with fetchProperties as the RootObject. Try something like this,
public class MyClass
{
[JsonProperty("fetchProperties")]
public Fetch FetchProperties { get; set; }
}
public class Fetch
{
[JsonProperty("properties")]
public List<string> Properties { get; set; }
}
private string FetchProperties()
{
MyClass obj = new MyClass()
{
FetchProperties = new Fetch()
{
Properties = new List<string>() { "ticketNumber", "driver.Name" }
}
};
return JsonConvert.SerializeObject(obj); // Formatting.None is by default
}
Now its your choice to hard code these values or, pass them as arguments or use a local variable that contains a list of all the strings you intend to store as "properties". You cant use enums because of violation in naming convention (driver.name) so these options should suffice.

Configuration.GetSection() easily gets primitive string values but not complex values

This really amazes me. I am reading values from appsettings.json using Configuration.GetSection method and in nutshell my appsettings.json looks like below:
"AppSettings":
{
"PathPrefix": "",
"Something": "Something else",
"Clients":{"foo": "bar"}
}
Now I surprises me is that if I do something like below:
var foo = Configuration.GetSection("AppSettings:Clients:foo").Value;
Then it gets the value correctly. It gets the value bar
However, when I do
var clients = Configuration.GetSection("AppSettings:Clients").Value;
it returns null. It's not only this field, whenever I call getSection method to get any complex object then it returns null but when I call it to get a basic string value then it gets the value correctly even though seeminglyi, it had problems in getting its parent element. This baffles me and raises three questions:
Why would it have issues getting complex values but not getting basic string values?
Is it by design? If so , why?
If I want to load entire object, how do I do that?
You can load an entire object using a strongly typed object.
First, create a class (or classes) to hold you settings. Based on your example this would look like:
public class AppSettings
{
public string PathPrefix { get; set; }
public string Something { get; set; }
public Clients Clients { get; set; }
}
public class Clients
{
public string foo { get; set; }
}
Now, you need to add the Options service to your service collection and load your settings from the configuration:
public void ConfigureServices(IServiceCollection services)
{
// This is only required for .NET Core 2.0
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddMvc();
}
You now access the properties by injecting them into your class, for example:
public class HomeController : Controller
{
private readonly AppSettings _settings;
public HomeController(IOptions<AppSettings> settings)
{
_settings = settings.Value;
}
}
You can also load suboptions in the ConfigureService method by specifying the configuration section to load e.g.
services.Configure<Clients>(Configuration.GetSection("AppSettings:Clients");
Now you can inject IOptions<Clients> to access those settings
The official documentation can be found here
What would you expect it to return? You can get complex objects using the Get<T> extension method. Try this:
var clients = Configuration.GetSection("AppSettings:Clients").Get<YourClientsType>();

Update method in web API: How to know which fields to update?

I have a typical web API with a couple of PUT/UPDATE endpoints. These endpoints simply call the underlying service, and do the update.
The service layer, has the typical signature such as Object Update(Object object). What I then do is I basically run the following pseudo code:
var dbobject = _db.Object.Find(object.Id);
dbobject.Field1 = object.Field1;
dbobject.Field2 = object.Field2;
// continue for all fields
_db.SaveChanges();
return GetObjectById(object.Id);
However, this provides a challenge for me.
Lets say we have a consumer of our API. This consumer calls my PUT endpoint (/api/Object/{id}), and the payload is the updated Object.
However, lets say that the object we put don't know about example Field4, then this value would be NULL after the update has been run.
My question is:
What do you do about all those fields the payload does NOT contain?
How do you handle not setting values to NULL you don't expect to be
NULL afterwards?
As one of the possible ways, here can be used mix of NotifyPropertyChanged with automapper
The Idea is to store in DTO object which fields exactly was set, and which stays filled with default value. And use collected data in mapping.
For example DTO object will be
public class Dto
{
private List<string> Changed = new List<string>();
public bool IsChanged(string field) => Changed.Contains(field);
private int _age;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
// IMPORTANT: field name should fit main object field name
Changed.Add("Name");
}
}
public int Age
{
get { return _age; }
set
{
_age = value;
Changed.Add("Age");
}
}
}
I used Next class for test
public class Human
{
public string Name { get; set; } = "DEFAULT";
public int Age { get; set; } = -1;
}
and automapper configuration will looks like
cfg.CreateMap<Dto, Human>()
.ForAllMembers(s=> s.Condition(d=>d.IsChanged(s.DestinationMember.Name)));
This is a simple example. But it still doesn't prevent to use function IsChanged for some complex/specific logic, use not just a strings but Expressions / MethodInfo, or add custom attributes and use them in automapper configuration (DestinationMember is MethodInfo)
Append
Instead of complex DTO object the information about passed field you can get from Request.Properties in your controller (key ms_querynamevaluepairs value of type Dictionary<string, string>).

c# property contains only get,where the value set from App.config

I have a sample c# application.
In the App.config file there is parameters such as add key="access" value="abcd" inside appSettings tag and in other class file there is a get property such as
public string Access { get; } from where I am getting the value abcd.Here there is no set property.But I am getting the value of access as abcd and its working fine.
My question is, where the value of access in App.config is set in the application.
A readonly property still can be set from within the class that defines the property. And that's what is happening here.
Pseudo code:
public class Settings
{
private string _access;
public Settings()
{
_access = read from config;
}
public string Access { get { return _access; } }
}

Categories

Resources