I've been working on my software lately and I have been wondering what the best way is to store an associative array.
The only thing I could come up with out of the blue is to do something like this:
<add key="disks" value="C|1|10,D|2|20,E|1|5,Z|1|3"/>
But this doesn't offer a lot of readability in my config file and I want my config file to be readable as it is a console application.
The reason for this because I've written a program that checks the diskspace of the disks specified in the app.config file but I want different thresholds for different disks.
How would you solve it?
Here's a part of my current config file.
<!-- DISK FEATURE SETTINGS -->
<!-- Type 1 is threshold by percentage and type 2 is threshold by a certain limit -->
<add key="threshold_type" value="1" />
<add key="threshold_limit" value="0,1" />
<!-- Space_type defines if you want to limit using kilobytes (1), megabytes (2) or gigabytes (3) if using threshold_type 2 -->
<add key="space_type" value="3" />
<!-- Put the disks here delimited by a comma like this: C,D,E -->
<add key="disks" value="C,D,E,Z"/>
<!-- SERVICE FEATURE SETTINGS -->
<!-- Put the services here delimited by a comma like this: C,D,E -->
<add key="services" value="spooler,ekrn,RadeonPro Support Service,TeamViewer6"/>
<!-- Put this on 1 if you want to log your output to a text file -->
<add key="logging" value="1"/>
I want to use the same principle for my performancecounter program that uses the perfmon counters to get some data and store it in a text file.
I hope people can help me for a bit here :)
I suggesst you to create your own configuration section. Custom configuration gives more readability and type safety. Here are links to create custom configuration
http://msdn.microsoft.com/en-us/library/2tw134k3.aspx and
http://haacked.com/archive/2007/03/11/custom-configuration-sections-in-3-easy-steps.aspx (old one but easy to follow).
As far as standard configuration mechanism works with XML serialization, the best (and, IMHO, the wise) way to store dictionaries in App.config is a List<KeyValuePair<K,V>>.
you may want to use Hashtable from system.collection or List<>
below are few pointers for hashtable,
http://www.dotnetperls.com/hashtable
http://www.tutorialspoint.com/csharp/csharp_hashtable.htm
i hope this helps!! thanks :)
Related
I've got an application that runs without problem with the File and Console Sinks and now I'm trying to add the MSSqlServer Sink.
Looking at the documentation on Github I've got my application to write to the SQL Database as well as the other sinks.
<add key="serilog:write-to:MSSqlServer.connectionString" value="Server=servername;Database=databasename;User Id=userid;Password=password;"/>
<add key="serilog:write-to:MSSqlServer.tableName" value="Logs"/>
<add key="serilog:write-to:MSSqlServer.autoCreateSqlTable" value="true"/>
One improvement is I'd like to add a custom column to the Logs table that Serilog uses to store a number indicating a unique RunId for my application. The idea being that a simple query would allow grouping by RunId to see all messages for that one run.
So I added the following, based on the documentation (and I haven't been able to find any other examples) as it seemed logical:
<add key="serilog:write-to:MSSqlServer.columnOptions.ColumnName" value="RunId"/>
<add key="serilog:write-to:MSSqlServer.columnOptions.PropertyName" value="RunId"/>
<add key="serilog:write-to:MSSqlServer.columnOptions.DataType" value="SqlDbType.Int"/>
<add key="serilog:write-to:MSSqlServer.columnOptions.DataLength" value="32"/>
and then in my code all I need to do is:
Log.Information("{RunId}{Message}", RunId, Message);
to see a new entry with {RunId} in the RunId column and {Message} in the Message column... however everytime I do this nothing is written to the RunId column, it remains as NULL whereas every log message the console/file has is also duplicated in the Table.
So it seems logging is working, it must be the keys wrong and I'm really not sure what should be used.
Would anyone be able to point me in the direction I need to be going or where I've gone wrong?
Thank you.
Logging definitely was working but some digging and finally I found out I had two issues:
Permissions on database where insuffident for the user serilog was using, and
AppSettings settings I was using were wrong
#1 was easy enough to fix, I created a dedicated Serilog account for this database and fixed the permissions as per documentation.
#2 however was very frustrating but eventually I was able to get the following to work:
<configSections>
<section name="MSSqlServerSettingsSection" type="Serilog.Configuration.MSSqlServerConfigurationSection, Serilog.Sinks.MSSqlServer"/>
</configSections>
<MSSqlServerSettingsSection DisableTriggers="false" ClusteredColumnstoreIndex="false" PrimaryKeyColumnName="Id">
<!-- SinkOptions parameters -->
<TableName Value="Logs"/>
<Columns>
<add ColumnName="RunId" DataType="int"/>
</Columns>
</MSSqlServerSettingsSection>
On compile and execution my program will now create the Logs table in the database and then create a RunId column which I have been able to populate with a {RunId} expression in my Log.Debug() calls.
FWIW: I hope this will be helpful and if I can work out how I'll see if I can add this to documentation as an example of using AppSettings for this use case. Searching this question most people seem to be using JSON and not AppSettings.
I would like to know if it is possible to write the logs to another target if the message that we want to write begins with certain words, a prefix.
I can't do it at the class level right now, that's why I'm checking if it's possible to get what I want in an easier way than modifying the code
Yes, this is possible.
It could be configured like this:
<logger name="*" writeTo="target-only-if-message-has-prefix">
<filters defaultAction='Ignore'>
<when condition="starts-with('${message}', 'MyPrefix')" action="Log" />
</filters>
</logger>
See
https://github.com/NLog/NLog/wiki/Filtering-log-messages
https://github.com/NLog/NLog/wiki/When-filter
I have an application that reads the app.config of a separate application. The app.config contains a collection of heterogeneous elements. The application I'm building will generate a TreeView control that displays the app.config custom section. the Save() method of the configuration object works fine unless I drill down and read/display the contents of the custom section. I followed this as an example (also found here). The issue seems to be that when I'm saving (after viewing and regardless if I make changes to the underlying config) the GetElementKey method is called. This returns the Key value of the element collection. But then this value is passed to the CreateNewElement method. This causes a problem because CreateNewElement passes back a new type depending on what elementName is passed in. At this point the element name isn't being passed in, just the key value.
The other strange thing I've noticed, from stepping through the code several times, is that if I don't read the values from the config to build the UI to display them, I hit the GetElementKey twice per element in the collection and CreateNewElement is not called at all. What happens when I do display values is that GetElementKey is called the same number of times. However, it comes back and is called again and then CreateNewElement is called with the key value as described above. Hopefully someone can describe to me what's going on under the hood that's causing this sequence of events to occur. Is there a property I need to change when deserializing the xml to the configuration objects?
This is the way I have my app.config structured:
<configuration>
<configSections>
<section name="section1" type="example" />
</configSections>
<section1>
<node1>
<elementA name="anElement" />
</node1>
<node2>
<add key="1" value="foo" />
</node2>
<node3>
<elementB>
<elementC name="anElement"/>
<elementD >
<elementE>
<foo name="foo1" />
<bar name="bar1" />
</elementE>
<elementF>
<elementG />
</elementF>
</elementD>
</elementB>
</section1>
</configuration>
The issues is regarding the collection in node section1/node3/elementD/elementE. After GetElementKey is called on "foo" and "bar" (2 times each) then it is called again and "foo1" is passed to CreateNewElement and that's when things break down.
I'm trying to pass 5MB~ data from a service to an actor, and I'm getting the error:
Fabric Message is too large
How can I increase the maximum size that can be transferred between micro-services?
I looked at the following page to see my options.
I tried setting:
<Section Name="ServiceReplicatorConfig">
...
<Parameter Name="MaxReplicationMessageSize" Value="1073741824" />
</Section>
Please help.
Somebody helped me on GitHub with the following:
In order to set maximum size for the remoting transport, you can use the following attribute and place it on your actor interface assembly or configure the maximum message size in the ServiceProxyFactory and ServiceRemotingListener creation.
[assembly: FabricTransportActorRemotingProvider(MaxMessageSize = 1073741824)]
https://msdn.microsoft.com/en-us/library/azure/microsoft.servicefabric.actors.remoting.fabrictransport.fabrictransportactorremotingproviderattribute.aspx
The discussion in GitHub.
Can you just pass a reference to that data like a URL to a blob/document storage? Passing 5MB of data within the SF service/actors is quite big and SF is not designed to store that big of data or state.
My app allows the user to specify in App.config the columns they want in their output:
<?xml version="1.0"?>
<configuration>
<appSettings>
.
.
.
<!-- specify columns you want -->
<add key="NameCol" value="true"/>
<add key="AddressCol" value="true"/>
<add key="TelCol" value="true"/>
.
.
.
</appSettings>
I have a separate project that tests my app. In the tests I change various column settings and after each test clear the settings using code like this:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// set config options here
// now clear config options
config.AppSettings.Settings.Remove("NameCol");
config.AppSettings.Settings.Remove("AddressCol");
config.AppSettings.Settings.Remove("TelCol");
Is there a way to read the column names from the App.config file and have a for loop for the above? So it would be something like this. What would getColNamesFromAppConfig() looklike?
columnNames = getColNamesFromAppConfig()
foreach (string colName in ColumnNames)
{
config.AppSettings.Settings.Remove(colName);
}
How about:
foreach (SettingsProperty property in Settings.Properties) // or ConfigurationProperty?
{
// ...
}
PS. By the way, if I were you, I would consider wrapping settings in a custom object (implemented by yourself). If you have to do this:
config.AppSettings.Settings.Remove("NameCol");
config.AppSettings.Settings.Remove("AddressCol");
config.AppSettings.Settings.Remove("TelCol");
in a test, it's a code smell to me. I believe you should be able to mock settings for testing purposes. This is a matter of taste, however.