I am trying to use a Singleton backed with an XML file for my application configurations.
My Singleton looks like this:
public sealed class AppConfig
{
private static readonly Lazy<AppConfig> appConfig = new(() => new AppConfig());
public static AppConfig Settings
{
get { return appConfig.Value; }
}
private AppConfig()
{
}
[XmlElement]
public string SomeValue { get; set; }
}
To write the contents of the Singleton to disk I can use:
var xs = new XmlSerializer(typeof(AppConfig));
var sw = new StreamWriter(fileName);
xs.Serialize(sw, AppConfig.Settings);
The obvious code to read the XML file back into the Singleton results in a compile error, because of course the instance is readonly
var sr = new StreamReader(fileName);
AppConfig.Settings = (AppConfig)xs.Deserialize(sr);
Error CS0200
Property or indexer 'AppConfig.Settings' cannot be assigned to -- it is read only
An option I have found is to create another class that holds the values and make this a property of the singleton. Then this class gets serialized, eg:
public sealed class AppConfig
{
private static readonly Lazy<AppConfig> appConfig = new(() => new AppConfig());
public static AppConfig Settings
{
get { return appConfig.Value; }
}
private AppConfig()
{
Values = new Values();
}
public Values Values { get; set; }
}
public class Values
{
[XmlElement]
public string SomeValue { get; set; }
}
To serialise/deserialise use the appropriate call on this, eg:
AppConfig.Settings.Values = (Values)xs.Deserialize(sr);
While what I have come up with works, it seems a bit convoluted, and the access path to the variables is of course longer.
Is there a better way to deserialise into the Singleton?
Is it a safe option just to remove the readonly?
Related
I have a class which contains readonly private fields
public sealed class Company : AggregateRoot
{
private readonly List<TimeSeriesImportInfo> _executedImportInfo = new();
private readonly List<StockPrice> _stockPrices = new();
public Company(
Guid id,
string name,
string symbol)
: base(id)
{
Name = name;
Symbol = symbol;
}
public string Name { get; }
public string Symbol { get; }
public IReadOnlyCollection<TimeSeriesImportInfo> ExecutedImportInfo => _executedImportInfo.AsReadOnly();
public IReadOnlyCollection<StockPrice> StockPrices => _stockPrices.AsReadOnly();
public void AddExecutedImportInfo(DateTime month)
{
var timeSeriesImportInfo = new TimeSeriesImportInfo(month);
var hasAlreadyBeenHandled = ExecutedImportInfo.Contains(timeSeriesImportInfo);
if (hasAlreadyBeenHandled)
{
throw new ImportExecutedBeforeDomainException(Id, month);
}
_executedImportInfo.Add(timeSeriesImportInfo);
var importExecutedEvent = new ImportExecutedDomainEvent(Id, timeSeriesImportInfo.Month);
Enqueue(importExecutedEvent);
}
public void AddStockPrices(ICollection<StockPrice> stockPrices)
{
var hasAlreadyBeenImported = stockPrices.Any(newStockPrice =>
_stockPrices.Contains(newStockPrice));
if (hasAlreadyBeenImported)
{
throw new StockPriceAlreadyImportedDomainException(Id, stockPrices);
}
_stockPrices.AddRange(stockPrices);
var stockPricesAddedEvent = new StockPricesAddedDomainEvent(Id, stockPrices);
Enqueue(stockPricesAddedEvent);
}
}
I have configured the mapping for the company using the following method:
public static class Mapping
{
public static IServiceCollection AddMappings(this IServiceCollection services)
{
BsonClassMap.RegisterClassMap<Company>(classMap =>
{
classMap.AutoMap();
classMap.MapField("_executedImportInfo").SetElementName(nameof(Company.ExecutedImportInfo));
classMap.MapField("_stockPrices").SetElementName(nameof(Company.StockPrices));
});
return services;
}
}
The values of those private readonly fields are correctly saved to the database. However when im trying to fetch company object - those private fields can't be deserialized properly, because after the fetch they have default values (although they are persisted in the db). If i removed the "readonly" keyword from them - everything works correctly. I would like to avoid removing the readonly key and would like to not modify the Company class. How to achieve that in C#? Thanks for any help, regards.
it's not supported, readonly fields are skipped during deserialization after ctor called.
I have a class with some static filds. When they are initialised they add themself to a Dictionary.
When the program starts a second time it tries to access the content of the Dictionary but since I haven't accessed any filds in the class (the Dictionary is in another) they can't be found.
I already understand that the static fields are initialised when I access one of them but are there any other ways to initialise them without calling any methods or fields for no other reason then nitialising them once?
----------------------
Here some code:
Resource.cs
public class Resource : InventoryItem
{
public const int IDBase = 1000000;
private Resource(int id) : base(IDBase + id) { }
public static Resource Hydrogen { get; } = new Resource(1); // H
public static Resource Helium { get; } = new Resource(2); // He
public static Resource Lithium { get; } = new Resource(3); // Li
public static Resource Beryllium { get; } = new Resource(4); // Be
public static Resource Boron { get; } = new Resource(5); // B
public static Resource Carbon { get; } = new Resource(6); // C
public static Resource Nitrogen { get; } = new Resource(7); // N
public static Resource Oxygen { get; } = new Resource(8); // O
// and all the other elements....
}
}
InventoryItem.cs
public abstract class InventoryItem
{
public int ID { get; }
private static readonly Dictionary<int, InventoryItem> idList = new Dictionary<int, InventoryItem>();
public InventoryItem(int id)
{
ID = id;
idList[id] = this;
}
public static InventoryItem GetFromID(int id)
{
return idList[id];
}
}
When I use InventoryItem.GetFromID(int id) before accessing anything from the Resource class the dictionary is empty and nothing can be found. If I access any resource before they are in the Dictionary.
As the static fields in a class are only initialized when you first use that class, you have to somehow force this initialization, e.g. by calling any static method in Resource.
Example:
in Resource, add
public static void Initialize()
{
// can be left empty; just forces the static fields to be initialized
}
and somewhere else in your project
Resource.Initialize();
Alternatively you could initialize them in a static constructor.
It's like a default constructor except it is static.
It is similar to Java's static { ... } block
public class Resource : InventoryItem
{
public const int IDBase = 1000000;
public static Resource Hydrogen { get; }
public static Resource Helium { get; }
public static Resource Lithium { get; }
// ...
private Resource(int id) : base(IDBase + id)
{
}
private static Resource()
{
Hydrogen = new Resource(1);
Helium = new Resource(2);
Lithium = new Resource(3);
// etc...
}
}
Caveat - I haven't actually tried this but I think it's likely to work.
Static fields and properties are initialized in a type constructor, regardless of how you write it, so both:
static Resource()
{
Hydrogen = new Resource(1);
}
and
Hydrogen { get; } = new Resource(1);
Are the same thing, the only difference is the initialization order, also it would allow you to call static fuctions, but in OP's case it really doesn't make a difference, that's why pamcevoy's answer won't work.
Klaus provides a valid way of doing things, and it will work, just you would need to call the Initialize method before your GetFromID, at least once, as to initialize all of the Resource class's static properties, e.g.:
Resource.Initialize();
InventoryItem.GetFromID(id);
Your last option is to do method shadowing, basically add to your Resource class the same GetFromID method with the new operator and then call GetFromID through the Resource class, e.g.
public class Resource : InventoryItem
{
public static new InventoryItem GetFromID(int id)
{
return InventoryItem.GetFromID(id);
}
}
But know that method shadowing isn't the same as overriding a method, so if you call InventoryItem.GetFromID you won't be calling Resource.GetFromID. This will eliminate the need for calling at startup a separate Initialize method in the Resource class but, it will force you to, at least once, call GetFromID through the Resource class.
Update: At the end of the day, the only way to initialize static fields/props is by accessing one thing or another in said class.
I've got options like this:
public class ApplicationSettings
{
public string Title { get; set; }
public string PluginFolders { get; set; }
}
and services like this:
public interface IWildcardResolver
{
string Resolve(string value);
}
public class WildcardResolver : IWildcardResolver
{
private readonly IHostingEnvironment _hostingEnvironment;
public WildcardResolver(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
AddWildcard("%contentRootPath%", _hostingEnvironment.ContentRootPath);
AddWildcard("%webRootPath%", _hostingEnvironment.WebRootPath);
AddWildcard("%environment%", _hostingEnvironment.EnvironmentName);
}
private readonly Dictionary<string, string> _hardWiredValues = new Dictionary<string, string>();
/// <inheritdoc />
public string Resolve(string value)
{
var sb = new StringBuilder(value);
foreach (var pair in _hardWiredValues)
{
sb.Replace(pair.Key, pair.Value);
}
return sb.ToString();
}
public void AddWildcard(string name, string value)
{
if (_hardWiredValues.ContainsKey(name))
throw new Exception($"A value for the wildcard {name} already exists.");
_hardWiredValues.Add(name, value);
}
}
How can i make sure that before i access those settings through DI with IOptions<AppSettings> PluginFolders is translated (because it contains wildcards)? I've tried IConfigureOptions<AppSettings> and IPostConfigureOptions<AppSettings> but both of them appear to happen at a stage too late. it's like i am missing a IPreConfigureOptions or something.
public class PluginManager
{
private readonly IOptions<ApplicationSettings> _settings;
public PluginManager(IOptions<ApplicationSettings> settings)
{
_settings = settings;
// how do i get an instance here which makes sure that the ApplicationSettings.PluginPaths is already manipulated without doing it manually?
}
}
Doing it like this works, but then it feels like i am fighting the framework since i can't use IOptions<AppSettings> like everywhere else:
Ok. I found it out by digging through some microsoft component sources.
This is the solution:
public class ApplicationSettingsSetup : IConfigureOptions<ApplicationSettings>
{
private readonly IWildcardResolver _wildcardResolver;
public ApplicationSettingsSetup(IWildcardResolver wildcardResolver)
{
_wildcardResolver = wildcardResolver;
}
/// <inheritdoc />
public void Configure(ApplicationSettings options)
{
options.PluginFolders = _wildcardResolver.Resolve(options.PluginFolders);
}
}
Registration:
services.AddTransient<IConfigureOptions<ApplicationSettings>, ApplicationSettingsSetup>();
services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
Previously i was loading the AppSettings from the Configuration and registering IConfigurationOptions afterwards. Somehow i assumed the factory which creates Options would know to call IConfigureOptions first before returning the IOptions instance - this is wrong.
Changing the order fixed it.
This looks more along the lines of what you are trying to achieve
services.AddOptions<ApplicationSettings>()
.Configure<IWildcardResolver>((options, wildcardResolver) => {
options.PluginFolders = wildcardResolver.Resolve(options.PluginFolders);
//...
});
The above registers an action used to configure a particular type of options. Note: These are run before all .
Reference Use DI services to configure options
I need to deserialize json for following class.
public class Test
{
public string Property { get; set; }
private Test()
{
//NOTHING TO INITIALIZE
}
public Test(string prop)
{
Property = prop;
}
}
I can create an instance of Test like
var instance = new Test("Instance");
considering my json something like
"{ "Property":"Instance" }"
How shall I create an object of Test class as my default constructor is private and I am getting object where Property is NULL
I am using Newtonsoft Json parser.
You can make Json.Net call the private constructor by marking it with a [JsonConstructor] attribute:
[JsonConstructor]
private Test()
{
//NOTHING TO INITIALIZE
}
Note that the serializer will still use the public setters to populate the object after calling the constructor.
Another possible option is to use the ConstructorHandling setting:
JsonSerializerSettings settings = new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};
Test t = JsonConvert.DeserializeObject<Test>(json, settings);
It doesn't seem like you need to take any extra steps.
Using Json.NET v6.0.8, the following C# program works inside LINQPad:
void Main()
{
var o = JsonConvert.DeserializeObject<Test>("{\"Property\":\"Instance\"}");
Debug.Assert(o.Property == "Instance",
"Property value not set when deserializing.");
}
public class Test
{
public string Property { get; set; }
private Test()
{
}
public Test(string propertyValue)
{
Property = propertyValue;
}
}
No need to create a Serializer setting and give assign ConstructorHandling here. Please remember to define the [JsonConstructor] attribute to the private constructor.
I have similar case with abstract BaseNode.cs and its concrete ComputerNode.cs implementation. You can create the classes, copy/paste the code below and do some experiment.
public abstract class BaseNode
{
[JsonConstructor] // ctor used when Json Deserializing
protected BaseNode(string Owner, string Name, string Identifier)
{
this.Name = Name;
this.Identifier = Identifier;
}
// ctor called by concrete class.
protected BaseNode(string [] specifications)
{
if (specifications == null)
{
throw new ArgumentNullException();
}
if (specifications.Length == 0)
{
throw new ArgumentException();
}
Name = specifications[0];
Identifier = specifications[1];
}
public string Name{ get; protected set; }
public string Identifier { get; protected set; }
}
public class ComputerNode: BaseNode
{
public string Owner { get; private set; }
[JsonConstructor] // not visible while creating object from outside and only used during Json Deserialization.
private ComputerNode(string Owner, string Name, string Identifier):base(Owner, Name, Identifier)
{
this.Owner = Owner;
}
public ComputerNode(string[] specifications):base(specifications)
{
Owner = specifications[2];
}
}
For JSon Read and Write following code helps -
public class Operation<T>
{
public string path;
public Operation()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "nodes.txt");
if (File.Exists(path) == false)
{
using (File.Create(path))
{
}
}
this.path = path;
}
public void Write(string path, List<T> nodes)
{
var ser = JsonConvert.SerializeObject(nodes, Formatting.Indented);
File.WriteAllText(path, ser);
}
public List<T> Read(string path)
{
var text = File.ReadAllText(path);
var res = JsonConvert.DeserializeObject<List<T>>(text);
return res;
}
}
All the best!
Today the short answer is: Rename the constructor parameter prop to property and your code will work fine.
public class Test
{
public string Property { get; }
public Test(string property)
{
Property = property;
}
}
Console.WriteLine(
JsonConvert.DeserializeObject(new Test("Instance")));
Newtonsoft.Json supports initializing properties using constructor parameters out of the box, without needing to set any additional attributes or changing any settings. The only constraint is that the parameter name needs to be a case insensitive match to the property name.
I discovered today that having a public constructor that takes parameters and no declared unparameterized constructor causes NewtonSoft to attempt to call the public constructor, the only one that it can find, since there is no explicit default constructor, and it cannot apparently find and call the default constructor provided by the framework unless it is the only constructor.
Explicitly declaring a default constructor causes NewtonSoft to call the correct (unparameterized) constructor.
In my .NET 4.0 application I'm accessing application properties through the interface ISettings I prepared:
public interface ISettings
{
int Quota { get; }
string Property2 { get; }
// ...
int PropertyN { get; }
}
// code generated by Visual Studio
public sealed partial class Settings :
global::System.Configuration.ApplicationSettingsBase
{
// application properties generated from app.config
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("123")]
public int Quota {
get {
return ((int)(this["Quota"]));
}
}
// and so on...
}
// my code to apply the interface to the Settings class
public sealed partial class Settings : ISettings
{
}
In some scenarios I would like to override the values from the config file depending on the organization I'm processing the data for, in example I would like to increase the quota for some organization. Of course, I could create the method similar to:
public int GetQuotaByOrgId(int orgId);
and implement the logic there, but I would like to avoid passing the orgId among the code. The better solution for me would be to create a proxy class overriding only the values I want to change, something like:
public class OverridenSettings : ISettings
{
private ISettings instance;
private int orgId;
private int[] orgsWithBiggerQuota = {1, 2, 132, 6542};
public OverridenSettings(ISettings instance, int orgId)
{
this.instance = instance;
this.orgId = orgId;
}
public override int Quota
{
get
{
int quota = this.instance.Quota;
if (this.orgsWithBiggerQuota.Contains(this.orgId))
{
quota += 1000;
}
return quota;
}
}
// all other properties should be taken from the default instance
}
Is there an elegant way to generate such class without having to explicitely implement all the interface's members just to redirect them to the default instance?
You can use any of the frameworks out there to create a dynamic proxy of your Settings class.
For example using Unity I can create an object of a class(in your case Settings class) like this
ISettings settings = (ISettings)Intercept.NewInstance(typeof(Settings), new VirtualMethodInterceptor(), new IInterceptionBehavior[] { new OrganizationInterceptor(orgId)});
The OrganizationInterceptor has the ability to 'intercept' method calls(including property getters/setters) and could have an implementation like:
public class OrganizationInterceptor : IInterceptionBehavior
{
private int OrgId { get; set; }
private List<int> orgsWithBiggerQuota;
public OrganizationInterceptor(int orgId)
{
OrgId = orgId;
WillExecute = orgId > 0;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var ret = getNext()(input, getNext);
if (input.MethodBase.IsSpecialName && input.MethodBase.Name == "get_Quota" &&
this.orgsWithBiggerQuota.Contains(OrgId))
ret.ReturnValue = (int)ret.ReturnValue + 100;
return ret;
}
public bool WillExecute { get; set; }
}
I haven't ran this myself so you might need to debug it a bit(especially the Invoke method).
If you want to use the VirtualMethodInterceptor you need to declare your property virtual. There is also TransparentProxyInterceptor which doesnt require this but will create another object that will call into your object(2 objects in total vs 1 in the virtual case).