Why does C# compiler includes non-public members in the XML documentation? - c#

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()

Related

Property of an AppModel application not getting updated in SCCM

I'm trying to update SDMPackageXML property of an AppModel application through C# code. SDMPackageXML is an XML property. I've to update only one node named AutoInstall in the
SDMPackageXML XML property. Here is my code:
ObjectGetOptions opt = new ObjectGetOptions(null, System.TimeSpan.MaxValue, true);
var path = new ManagementPath("SMS_Application.CI_ID=16777568");
ManagementObject obj = new ManagementObject(scope, path, opt);
obj.Get();
foreach (PropertyData property in obj.Properties)
{
if (property.Name == "SDMPackageXML")
{
//change the property value. Set AutoInstall to true
XmlDocument xml = new XmlDocument();
xml.LoadXml(property.Value.ToString());
var autoInstallTag = xml.GetElementsByTagName("AutoInstall");
autoInstallTag[0].InnerText = "false";
property.Value = xml.OuterXml;
}
}
obj.Put();
The problem is that obj.Put(); updates nothing on the SCCM server. Can someone help me please?
So similar to what I talked about in this answer the main problem here is that Microsoft uses a special method to serialize their XML. The deserialization still works with using the default classes but to serialize again there is no documentation as to how to (I'm pretty sure it is possible but I am not knowledgeable enough to do it)
Instead of documentation they provide wrapper classes for this which are shipped with the SCCM Console (Located in the bin directory of the Installation folder of the Console).
In this case this would be Microsoft.ConfigurationManagement.ApplicationManagement.dll. Unlike in powershell where the dependencies in the same path seem to be loaded as well you seem also to have to reference at least Microsoft.ConfigurationManagement.ApplicationManagement.TaskSequenceInstaller.dll as well.
There are also further dlls with names like Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll present however at least in my tests the two above were the only ones needed, but if you notice the deserialization failing with "InvalidPropertyException" errors you might need the dll matching your specific application type.
With those two dlls referenced you can write something like this (note I deserialized using the dll as well because why not if it is already loaded and it creates a nice application object to directly modify the properties. This is however technically not necessary. You could deserialize like in your example and only use the serialization part.
ManagementObject obj = new ManagementObject(#"\\<siteserver>\root\SMS\site_<sitecode>:SMS_Application.CI_ID=<id>");
Microsoft.ConfigurationManagement.ApplicationManagement.Application app = Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer.DeserializeFromString(obj["SDMPackageXML"].ToString(), true);
app.AutoInstall = true;
obj["SDMPackageXML"] = Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer.SerializeToString(app, true);
obj.Put();
Now one thing to keep in mind is that is can be a little tricky referencing the applications by their CI_ID because if you update the application the id for the currently valid version of the app changes (the old id still can be used to reference the older revision). So if you change the application gotten using the ID and then change it back with the same ID it will look like only the first change worked. I don't know if this is problematic for you (If you just get all IDs then change every application only once it should not matter) but if it does you can search for the application using their name plus isLatest = 'true' in the WQL query to always get the current one.

Check if current and external .Net process has performance counters enabled?

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

BizTalk Dynamic Disassembler Problems - The body part is NULL

I started with the solution here http://social.technet.microsoft.com/wiki/contents/articles/20547.biztalk-server-dynamic-schema-resolver-real-scenario.aspx
which matches my scenario perfectly except for the send port, but that isn't necessary. I need the receive port to choose the file and apply a schema to disassemble. From their the orchestration does the mapping, some of it custom, etc.
I've done everything in the tutorial but I keep getting the following error.
"There was a failure executing the receive pipeline... The body part is NULL"
The things I don't get from the tutorial but don't believe they should be an issue are:
I created a new solution and project to make the custompipeline component (reference figure 19) and thus the dll file. Meaning it is on it's own namespace. However, it looks like from the tutorial they created the project within the main biztalk solution (ie the one with the pipeline and the orchestration) and thus the namespace has "TechNetWiki.SchemaResolver." in it. Should I make the custompipeline component have the namespace of my main solution? I'm assuming this shouldn't matter because I should be able to use this component in other solutions as it is meant to be generic to the business rules that are associated with the biztalk application.
The other piece I don't have is Figure 15 under the "THEN Action" they have it equal the destination schema they would like to disassemble to but then they put #Src1 at the end of "http://TechNetWiki.SchemaResolver.Schemas.SRC1_FF#Src1". What is the #Src1 for?
In the sample you've linked to, the probe method of the pipeline component is pushing the first 4 characters from the filename into a typed message that is then passed into the rules engine. Its those 4 characters that match the "SRC1" in the example.
string srcFileName = pInMsg.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties This link is external to TechNet Wiki. It will open in a new window. ").ToString();
srcFileName = Path.GetFileName(srcFileName);
//Substring the first four digits to take source code to use to call BRE API
string customerCode = srcFileName.Substring(0, 4);
//create an instance of the XML object
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(string.Format(#"<ns0:Root xmlns:ns0='http://TechNetWiki.SchemaResolver.Schemas.SchemaResolverBRE This link is external to TechNet Wiki. It will open in a new window. '>
<SrcCode>{0}</SrcCode>
<MessageType></MessageType>
</ns0:Root>", customerCode));
//retreive source code in case in our cache dictionary
if (cachedSources.ContainsKey(customerCode))
{
messageType = cachedSources[customerCode];
}
else
{
TypedXmlDocument typedXmlDocument = new TypedXmlDocument("TechNetWiki.SchemaResolver.Schemas.SchemaResolverBRE", xmlDoc);
Microsoft.RuleEngine.Policy policy = new Microsoft.RuleEngine.Policy("SchemaResolverPolicy");
policy.Execute(typedXmlDocument);
So the matching rule is based on the 1st 4 characters of the filename. If one isn't matched, the probe returns a false - i.e. unrecognised.
The final part is that the message type is pushed into the returned message - this is made up of the namespace and the root schema node with a # separator - so your #src1 is the root node.
You need to implement IProbeMessage near to class
I forgot to add IProbeMessage in the code of article. It is updated now.
but it is there in sample source code
Src1 is the the root node name of schema. I mentioned that in article that message type is TargetNamespace#Root
I recommend to download the sample code
I hope this will help you

How to change the name of a NetworkAdapter in c#?

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

Automatically generating code from a text or xml file and then compiling?

I would like to know how I could generate code from a text file in a particular format into a VB.net or C# source file.
For instance: I would like my code generating program to read text file having the following format:
<category1>
<subcategory>
entry1
entry2
</subcategory>
</Category1>
And then generate code in vb.net(or C#):
Dim TreeNode1 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("entry1")
Dim TreeNode2 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("entry2")
Dim TreeNode3 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("subcategory", New System.Windows.Forms.TreeNode() {TreeNode1, TreeNode2})
The idea is to compile the main code after the user have modified the txt file and used the code generating program. I would prefer to write the code generating program in C, python or C#.
How can I go about this?
I'm not really convinced this is a python question, despite the tags and penultimate sentence in the question, but here's a python answer.
>>> from xml.etree import ElementTree as etree
>>> corpus = '''<category1>
... <subcategory>
... entry1
... entry2
... </subcategory>
... </category1>
... '''
>>> doc = etree.fromstring(corpus)
>>> for subcategory in doc.getchildren():
... for entry in filter(bool,
... map(str.strip,
... subcategory.text.split('\n'))):
... print "entry output: (%s)" % entry
... print "subcategory output (%s)" % subcategory.tag
...
entry output: (entry1)
entry output: (entry2)
subcategory output (subcategory)
>>>
You need to write parser to parse your text file. Once parser generate string which is similar to VB.net or C# code, you can use Emit to compile to a temporary assembly
Use the CSharpCodeProvider, set up a string skeleton that is the rest of you class, parse your file, and then inject your generated code in the correct location.
Info about the CSharpCodeProvider
Note that you will want to build in memory and set build executable to false. Here is an example on how to do that, it also shows how set the assemblies for the compiler to the assemblies of the currently executing file.
I know this is a bit vague but how you set up the actual CSharpCodeProvider depends on what you are trying to do. Also beware that if you get FileNotFound exceptions you are getting compile errors, the top link gives a nice solution on how to throw them in a readable fashion.
This depends on which of mentioned languages is most familiar to you. I'd recommend to go with python, because you can start playing with it right away from command line interpreter.
There is standard library for xml parsing:
from xml.dom.minidom import parse, parseString
dom1 = parse('c:\\temp\\mydata.xml') # parse an XML file by name
Then you iterate through elements, either by name, like this:
for node in dom1.getElementsByTagName('category1'):
...
or straight-forward for all elements:
for node in dom1.childNodes:
...
Below is the command line interpreter transcript of how to inspect the object tree (>>> stand for interpreter prompt):
$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> dom = parseString ('<root>contents</root>')
>>> dom.childNodes
[<DOM Element: root at 0x7f0d4519f680>]
>>> dom.childNodes[0]
<DOM Element: root at 0x7f0d4519f680>
>>> dom.childNodes[0].childNodes
[<DOM Text node "u'contents'">]
>>> dom.childNodes[0].childNodes[0]
<DOM Text node "u'contents'">
>>> dom.childNodes[0].childNodes[0].nodeValue
u'contents'
>>>

Categories

Resources