In C# or else VB.Net, and having only a PID of a process, I wonder if it can be possibly to check at execution time whether the associated process has performance counters enabled.
I'll mean when the performanceCounters setting is enabled in its app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...
<system.net>
<settings>
<performanceCounters enabled="true"/>
</settings>
</system.net>
...
</configuration>
However, I'm asking about the possible existance of a proper/built-in solution using reflection, or other .Net Framework members than doing a primitive check for an app.config file and then parsing the file to find the setting, I'm aware of that, its what I'm trying to avoid.
As a secondary question I will ask:
How I could check for the same thing in the current process?,
I ask this because maybe the methodology to determine whether performance counters are enabled in the current process could be easier than determining it in an external process (but again I'm asking this for a solution to avoid parsing the app.config file).
You specifically want to avoid parsing the app.config file, but frankly I would. Your question suggest you don't want to "manually" parse the app.config, which you don't have to (So I'll be stubborn on suggest the following ;-))
Check for the current process:
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var group = (NetSectionGroup)config.GetSectionGroup("system.net");
if (group.Settings.PerformanceCounters.Enabled)
{
Console.WriteLine("ENABLED");
}
Check for other processes, well executables really.
var config = ConfigurationManager.OpenExeConfiguration(#" ... path to other executable ... ");
var group = (NetSectionGroup)config.GetSectionGroup("system.net");
if (group.Settings.PerformanceCounters.Enabled)
{
Console.WriteLine("ENABLED");
}
Usually all per-process Performance Counters have PID (or process name or some other identifying information) embedded in Performance Counters Instance Names:
(the part highlighted in yellow is the PID).
So if Process ID is what you have, you can search around instance names for this substring.
I did this Generic usage function for future needs with App config file, maybe it will not be able to parse the tree level architecture in all scenarios, but hey, its just a start.
Usage:
GetAppConfigSetting(Of Boolean)("system.net", "settings", "performanceCounters", "enabled"))
Source:
Public Shared Function GetAppConfigSetting(Of T)(ByVal sectionGroupName As String,
ByVal sectionName As String,
ByVal elementName As String,
ByVal propertyName As String,
Optional ByVal exePath As String = "") As T
Dim appConfig As Configuration
Dim group As ConfigurationSectionGroup
Dim section As ConfigurationSection
Dim sectionPropInfo As PropertyInformation
Dim element As ConfigurationElement
Dim elementPropInfo As PropertyInformation
If Not String.IsNullOrEmpty(exePath) Then
appConfig = ConfigurationManager.OpenExeConfiguration(exePath)
Else
appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
End If
group = appConfig.GetSectionGroup(sectionGroupName)
If group Is Nothing Then
Return Nothing
End If
section = group.Sections(sectionName)
If section Is Nothing Then
Return Nothing
End If
sectionPropInfo = section.ElementInformation.Properties(elementName)
If sectionPropInfo Is Nothing Then
Return Nothing
End If
element = DirectCast(sectionPropInfo.Value, ConfigurationElement)
If element Is Nothing Then
Return Nothing
End If
elementPropInfo = element.ElementInformation.Properties(propertyName)
If elementPropInfo Is Nothing Then
Return Nothing
End If
Return DirectCast(elementPropInfo.Value, T)
End Function
Related
When you compile your source code using csc.exe, you can use /doc option to save your xml documentation comments that are in the source file to an external xml file.
What I want to know is why the compiler includes the xml comments of the non-public members of my code in that file. Since I already have the documentation in the source code, I don't need anything that's in the xml documentation file while working on that project.
And if I use the dll for another project, I can't use the non-public members anyway. So why does it contain documentation for all the private and internal members?
I would also like to know if there is a way to prevent that.
I can understand internal members being documented - that way it may be easier to browse the documentation for code you're writing within the same assembly. (And there's always InternalsVisibleTo, of course.) For private members, I think it's a bit harder to justify.
If you use Sandcastle to generate offline documentation, you can ask it to generate a new XML file with only the public members - and only the summary parts, at that. I can't remember offhand what it looks like in SHFB, but in our Noda Time project file, I believe this is the relevant section:
<ComponentConfig id="IntelliSense Component" enabled="True">
<component id="IntelliSense Component"
type="SandcastleBuilder.Components.IntelliSenseComponent"
assembly="{#SHFBFolder}SandcastleBuilder.Components.dll">
<output includeNamespaces="false" namespacesFile="Namespaces"
folder="{#OutputFolder}\..\PublicApi" />
</component>
</ComponentConfig>
Here's my VBScript to filter the xml documentation.
Change strInputFile, strOutputFile to your input and output XML documentation files. Also, change "arrWhiteList = Array ... " line, listing all types you'd like to have documentation for.
option explicit
const strInputFile = "C:\Temp\YourModule.XML"
const strOutputFile = "C:\Temp\YourModule.filtered.XML"
Dim arrWhiteList
arrWhiteList = Array( "MyNamespace.Type1", "MyNamespace.Type2", "MyNamespace.Type3" )
Function isNameOk( strName )
Dim className, i
for each className in arrWhiteList
i = InStr(strName, className)
if i = 3 Then
isNameOk = True
exit function
end if
Next
isNameOk = false
end function
Sub Main()
Dim objXml, dicToRemove
Set objXml = CreateObject("Msxml2.DOMDocument.6.0")
objXml.Load strInputFile
Set dicToRemove = CreateObject( "Scripting.Dictionary" )
Dim node, strName
for each node in objXml.documentElement.SelectNodes( "//member" )
strName = node.getAttribute( "name" )
if not isNameOk( strName ) then
dicToRemove.add node, ""
end if
Next
Dim nodeMembers, arrKeys
Set nodeMembers = objXml.documentElement.SelectSingleNode( "//members" )
arrKeys = dicToRemove.Keys
for each node in arrKeys
nodeMembers.removeChild node
next
objXml.save strOutputFile
End Sub
Call Main()
People claim the following VB script works for changing network adapter names. However I am having a decidedly difficult time trying to convert this to a c# appliaction that can do the same thing. The problem I seem to be facing is that calls to the NetworkInterface.Name is readonly.
Option Explicit
Const NETWORK_CONNECTIONS = &H31&
Dim sOldName= WScript.Arguments(0)
Dim sNewName= WScript.Arguments(1)
Dim objShell, objFolder, colItems, objItem
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(NETWORK_CONNECTIONS)
Set colItems = objFolder.Items
For Each objItem in colItems
If objItem.Name = sOldName Then
objItem.Name =sNewName
End If
Next
I found this which explains it a bit more: http://blogs.technet.com/b/heyscriptingguy/archive/2005/05/11/how-can-i-rename-a-local-area-connection.aspx.
Ok, so there are special folders where the NIC names are stored and you access those folders by binding to the them via the SHELL. How then do you do something like this in c#?
You can change the name of a NIC easily through the registry if you know how the registry structure works.
You will need the NetworkAdapters GUID in order to locate which path to open. To get the network adapter GUID I recommend first querying the WMI "Win32_NetworkAdapter" class. There is a GUID property along with all the other properties needed to identify specific adapters.
You will notice this GUID in the registry path: {4D36E972-E325-11CE-BFC1-08002BE10318}Visit link for information on it:
http://technet.microsoft.com/en-us/library/cc780532(v=ws.10).aspx
string fRegistryKey = string.Format(#"SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{0}\Connection", NIC_GUID);
RegistryKey RegistryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, #"\\" + Server.Name);
RegistryKey = RegistryKey.OpenSubKey(fRegistryKey, true); //true is for WriteAble.
RegistryKey.SetValue("Name", "<DesiredAdapterName>");
By design the windows UI will not allow for duplicate NIC names. However, you can force duplicate NIC names via the registry. We have done tests, there seem to be nothing critically effected by having duplicate names. Windows seems to still function fine. You just want to be wary about scripting against NIC names if you don’t incorporate anti-duplicate name logic.
To create uniqueness you can use the adapter index property associated with the WMI query.
You can use the System.Management assembly and use this class.
Follow the sample here - http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/727c8766-8189-4ad6-956d-958e52b97c05/
You can also create a VB.NET dll with the functionality you need and reference and call it from your C# code.
Here is a console app demonstrating the code (I tested and it works :)
Option Explicit On
Module Module1
Sub Main()
Const NETWORK_CONNECTIONS = &H31&
Dim sOldName = "Local Area Connection"
Dim sNewName = "Network"
Dim objShell, objFolder, colItems, objItem
objShell = CreateObject("Shell.Application")
objFolder = objShell.Namespace(NETWORK_CONNECTIONS)
colItems = objFolder.Items
For Each objItem In colItems
Console.WriteLine(objItem.Name)
If objItem.Name = sOldName Then
objItem.Name = sNewName
End If
Console.WriteLine(objItem.Name)
Next
End Sub
End Module
It prints out:
Local Area Connection
Network
I want to change the location where my application looks for the app.config file.
I know that I can use ConfigurationManager.OpenExeConfiguration() to access an arbitrary config file - however, when the .Net Framework reads the config file (for ConnectionStrings or EventSources, for instance), it will look at the default location. I want to actually change the location, globally for the entire .Net Framework (for my application, of course).
I also know that I can use AppDomainSetup to change the location of the app.config for a new AppDomain. However, that doesn't apply to the primary AppDomain of the application.
I also know that I can override function Main() and create a new AppDomain as above and run my application in that new AppDomain. However, that has other side-effects - for instance, Assembly.GetEntryAssembly() will return a null reference.
Given how everything else works in .Net, I would expect there to be some way to configure the startup environment of my application - via a Application Manifest, or some such - but I have been unable to find even a glimmer of hope in that direction.
Any pointer would be helpful.
David Mullin
I used the approach with starting another AppDomain from Main(), specifying the "new" location of the configuration file.
No issues with GetEntryAssembly(); it only returns null, when being called from unmanaged code - or at least it doesn't for me, as I use ExecuteAssembly() to create/run the second AppDomain, much like this:
int Main(string[] args)
{
string currentExecutable = Assembly.GetExecutingAssembly().Location;
bool inChild = false;
List<string> xargs = new List<string>();
foreach (string arg in xargs)
{
if (arg.Equals("-child"))
{
inChild = true;
}
/* Parse other command line arguments */
else
{
xargs.Add(arg);
}
}
if (!inChild)
{
AppDomainSetup info = new AppDomainSetup();
info.ConfigurationFile = /* Path to desired App.Config File */;
Evidence evidence = AppDomain.CurrentDomain.Evidence;
AppDomain domain = AppDomain.CreateDomain(friendlyName, evidence, info);
xargs.Add("-child"); // Prevent recursion
return domain.ExecuteAssembly(currentExecutable, evidence, xargs.ToArray());
}
// Execute actual Main-Code, we are in the child domain with the custom app.config
return 0;
}
Note that we are effectively rerunning the EXE, just as a AppDomain and with a different config. Also note that you need to have some "magic" option that prevents this from going on endlessly.
I crafted this out from a bigger (real) chunk of code, so it might not work as is, but should illustrate the concept.
I am not sure why you want to change the location of your config file - perhaps there can be different approach for solving your actual problem. I had a requirement where I wanted to share configuration file across related applications - I had chosen to use own xml file as it had given me extra benefit of having complete control over the schema.
In your case, it's possible to externalize sections of your config file to a separate file using configSource property. See here under "Using External Configuration Files" to check how it has been done for connection strings section. Perhaps, this may help you.
var configPath = YOUR_PATH;
if (!Directory.Exists(ProductFolder))
{
Directory.CreateDirectory(ProductFolder);
}
if (!File.Exists(configPath))
{
File.WriteAllText(configPath, Resources.App);
}
var map = new ExeConfigurationFileMap
{
ExeConfigFilename = configPath,
LocalUserConfigFilename = configPath,
RoamingUserConfigFilename = configPath
};
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
Then use config member as you want.
Another approach is to leave the config file with the executable file and move the relevant changeable sections to external xml files which can be in whatever location you choose.
If you are using your config file in a readonly capacity, then you can add the relevant chunks to an XML file in a different location using XML Inlcude. This won't work if you are trying to write values back directly to app.config using the Configuration.Save method.
app.config:
<?xml version="1.0"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
<appSettings>
<xi:include href="AppSettings.xml"/>
</appSettings>
<connectionStrings>
<xi:include href="ConnectionStrings.xml"/>
</connectionStrings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/></startup>
</configuration>
ConnectionStrings.xml:
<?xml version="1.0"?>
<add name="Example1ConnectionString"
connectionString="Data Source=(local)\SQLExpress;Initial Catalog=Example1DB;Persist Security Info=True;User ID=sa;Password=password"
providerName="System.Data.SqlClient" />
<add name="Example2ConnectionString"
connectionString="Data Source=(local)\SQLExpress;Initial Catalog=Example2DB;Persist Security Info=True;User ID=sa;Password=password"
providerName="System.Data.SqlClient" />
AppSettings.xml:
<?xml version="1.0"?>
<add key="Setting1" value="Value1"/>
<add key="Setting2" value="Value2"/>
A file URI looks like this:
file:///C:/whatever.txt
You can even define failover files in case the one you are trying to reference is missing. This pattern is from https://www.xml.com/pub/a/2002/07/31/xinclude.html:
<xi:include href="http://www.whitehouse.gov/malapropisms.xml">
<xi:fallback>
<para>
This administration is doing everything we can to end the stalemate in
an efficient way. We're making the right decisions to bring the solution
to an end.
</para>
</xi:fallback>
I am trying to use a config file in my C# console application. I created the file within the project by going New --> Application Configuration File, and naming it myProjectName.config. My config file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SSDirectory" value="D:\Documents and Settings\****\MyDocuments\****" />
</appSettings>
</configuration>
The code to access it looks like this:
private FileValidateUtil()
{
sSDirFilePath = ConfigurationSettings.AppSettings["SSDirectory"];
if (sSDirFilePath == null)
Console.WriteLine("config file not reading in.");
}
Can anyone lend a hint as to why this is not working? (I am getting the error message.)
Thanks!!
badPanda
You can't change the name from app.config and expect ConfigurationManager to find it without providing it more information. Change the name of myProjectName.config back to app.config, rebuild, and you will see a file in the bin folder called myProjectName.exe.config. Then your call to ConfigurationManager.AppSettings should work correctly.
check the documentation
http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
First off, use ConfigurationManager instead of ConfigurationSettings.
Second, instead of saying "doesn't work", which provides no useful information, tell us what you're seeing. Does it compile? Does it throw an exception at runtime? Does your PC start to smoke and smell like melting plastic?
Try this:
public string GetSSDirectory()
{
string sSDirFilePath = string.Empty;
if (!ConfigurationManager.AppSettings.AllKeys.Contains("SSDirectory"))
{
Console.WriteLine("AppSettings does not contain key \"SSDirectory\"");
}
else
{
sSDirFilePath = ConfigurationManager.AppSettings["SSDirectory"];
Console.WriteLine("AppSettings.SSDirectory = \"" + sSDirFilePath + "\"");
}
return sSDirFilePath;
}
Has anyone got this working in a web application?
No matter what I do it seems that my appSettings section (redirected from web.config using appSettings file=".\Site\site.config") does not get reloaded.
Am I doomed to the case of having to just restart the application? I was hoping this method would lead me to a more performant solution.
Update:
By 'reloading' I mean refreshing ConfigurationManager.AppSettings without having to completely restart my ASP.NET application and having to incur the usual startup latency.
Make sure you are passing the correct case sensitive value to RefreshSection, i.e.
ConfigurationManager.RefreshSection("appSettings");
This seems to be a flaw (maybe a bug) when using an external config file for your appSettings. I've tried it using the configSource attribute and RefreshSection simply never works, I'm assuming this is the same when using the file attribute.
If you move your appSettings back inside your web.config RefreshSection will work perfectly but otherwise I'm afraid you're doomed.
For some reason ConfigurationManager.RefreshSection("appSettings") wasn't working for me. Reloading the Web.Config into a Configuration object seems to work correctly. The following code assumes the Web.Config file is one directory below the executing (bin) folder.
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
Uri uriAssemblyFolder = new Uri(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase));
string appPath = uriAssemblyFolder.LocalPath;
configMap.ExeConfigFilename = appPath + #"\..\" + "Web.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
And is used like:
string webConfigVariable = config.AppSettings.Settings["webConfigVariable"].Value;
.RefreshSection() does not work when the appSettings is external.
You can however use the following to change a value:
ConfigurationManager.AppSettings.Set(key, value)
This will NOT change the setting on file, only the loaded value in memory.
So instead of using RefreshSection I did the following:
string configFile="path to your config file";
XmlDocument xml = new XmlDocument();
xml.Load(configFile);
foreach (XmlNode node in xml.SelectNodes("/appSettings/add"))
{
string key = node.Attributes["key"].Value;
string value= node.Attributes["value"].Value;
ConfigurationManager.AppSettings.Set(key, value);
}
Any subsequent calls to AppSettings.Get will contain the updated value.
The appSettings will then be updated without needing to restart the application.
As an alternative you could write your own ConfigSection and set restartOnExternalChanges="false".
Then, when reading the section with ConfigurationManager.GetSection("yourSection") the settings will be auto-refreshed without an application restart.
And you could implement your settings strongly typed or as NameValueCollection.
Yes. you are stuck with iis restarting.
There is a feature with asp.net 4.0 and iis 7.5 where the initial startup is removed.
I am not sure if this is possible in a web app, but it works in a desktop app. Try using ConfigurationSettings rather than ConfigurationManager (it will yell at you for using outdated classes...), then reading all the data into a class. When you wish to refresh, simply create a new instance and drop all references to the old instance. My theory for why this works (might be wrong): when you don't directly access the app.config file the entire time you are running, the file lock is dropped by the application. Then, edits can be made when you are not accessing the file.
The App.Config settings are cached in memory when the application starts. For this reason, I don't think you'll be able to change those settings without restarting your application. One alternative that should be pretty straight forward would be to create a separate, simple XML configuration file, and handle loading/caching/reloading it yourself.
To write, call it this way:
Dim config As System.Configuration.Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
Return AddOrUpdateAppSetting(config, "YourSettingKey", "YourValueForTheKey")
To read and be sure you get the values in file, instead of those in cache, read it this way:
Dim config As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Return config.AppSettings.Settings("TheKeyYouWantTheValue").Value
Full example:
Protected Shared Function AddOrUpdateAppSetting( _
ByVal Config As System.Configuration.Configuration _
, ByVal TheKey As String _
, ByVal TheValue As String _
) As Boolean</p>
Dim retval As Boolean = True
Dim Itm As System.Configuration.KeyValueConfigurationElement = _
Config.AppSettings.Settings.Item(TheKey)
If Itm Is Nothing Then
If Config.AppSettings.Settings.IsReadOnly Then
retval = False
Else
Config.AppSettings.Settings.Add(TheKey, TheValue)
End If
Else
' config.AppSettings.Settings(thekey).Value = thevalue
If Itm.IsReadOnly Then
retval = False
Else
Itm.Value = TheValue
End If
End If
If retval Then
Try
Config.Save(ConfigurationSaveMode.Modified)
Catch ex As Exception
retval = False
End Try
End If
Return retval
End Function
Have you tried storing your AppSettings in its own external file?
From app.config/web.config:
<appSettings configSource="appSettings.config"></appSettings>
appSettings.config:
<?xml version="1.0"?>
<appSettings>
<add key="SomeKey" value="SomeValue" />
</appSettings>
Changes made to appSettings.config should be reflected instantly.
More info:
http://msdn.microsoft.com/en-us/library/system.configuration.sectioninformation.configsource.aspx