{"id":1039,"date":"2010-11-05T10:25:23","date_gmt":"2010-11-05T10:25:23","guid":{"rendered":"https:\/\/www.wapshere.com\/missmiis\/?p=1039"},"modified":"2010-11-05T10:25:23","modified_gmt":"2010-11-05T10:25:23","slug":"xml-lookup-file","status":"publish","type":"post","link":"https:\/\/www.wapshere.com\/missmiis\/xml-lookup-file","title":{"rendered":"XML Lookup file"},"content":{"rendered":"<p>On my first ever MIIS project we were an OCG customer so were able to use their nice XML library. I can&#8217;t remember in great detail what it did, but I&#8217;ve always considered the concept a best practise: if there&#8217;s anything that you find yourself hard-coding as a constant value in extension code, then you should put it in a lookup file, where you can change the values later without having to recompile the code.<br \/>\n<!--more--><\/p>\n<p>I&#8217;ve been working on a couple of projects this year which are big and complicated enough to warrant a proper lookup file, so I&#8217;ve finally had to get in and figure out how to parse XML in .NET. As usual this post is just about things I&#8217;ve been doing and I&#8217;m not trying to say this is the best way to go. You will have to adapt to your own requirements.\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0<\/p>\n<h3>The Structure of the XML File<\/h3>\n<p>The general outline of my XML file is to have a section for Global settings, and then individual sections for each MA. Note the &#8220;tag&#8221; for each MA, which I&#8217;ll be using in the code.\u00c2\u00a0\u00c2\u00a0The specifc values you include for each MA are entirely up to your requirements.<\/p>\n<pre>&lt;SyncParams&gt;\r\n  &lt;Global&gt;\r\n    &lt;SyncService&gt;\r\n      &lt;ServerName&gt;mysyncserver.mydomain.com&lt;\/ServerName&gt;\r\n      &lt;IsDev&gt;False&lt;\/IsDev&gt;\r\n    &lt;\/SyncService&gt;\r\n    &lt;SQL&gt;\r\n      &lt;Server&gt;mysqlserver.mydomain.com&lt;\/Server&gt;\r\n    &lt;\/SQL&gt;\r\n  &lt;\/Global&gt;\r\n  &lt;ManagementAgents&gt;\r\n    &lt;MA name='FIM Portal' tag='MAName_FIM'&gt;\r\n      &lt;maType&gt;FIM&lt;\/maType&gt;\r\n      &lt;MVobjectType&gt;person&lt;\/MVobjectType&gt;\r\n      &lt;MVobjectType&gt;group&lt;\/MVobjectType&gt;\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 &lt;MVobjectSource&gt;group&lt;\/MVobjectSource&gt;\r\n    &lt;\/MA&gt;\r\n    &lt;MA name='SQL HR Employees' tag='MAName_HR'&gt;\r\n      &lt;maType&gt;SQL&lt;\/maType&gt;\r\n      &lt;MVobjectType&gt;person&lt;\/MVobjectType&gt;\r\n      &lt;MVobjectSource&gt;person&lt;\/MVobjectSource&gt;\r\n    &lt;\/MA&gt;\r\n    &lt;MA name='Notes' tag='MAName_Notes'&gt;\r\n      &lt;maType&gt;NOTES&lt;\/maType&gt;\r\n      &lt;MVobjectType&gt;person&lt;\/MVobjectType&gt;\r\n      &lt;MVobjectSource&gt;person&lt;\/MVobjectSource&gt;\r\n    &lt;\/MA&gt;\r\n    &lt;MA name='AD mydomain' tag='MAName_AD'&gt;\r\n      &lt;maType&gt;AD&lt;\/maType&gt;\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 &lt;provEnabled&gt;True&lt;\/provEnabled&gt;\r\n      &lt;MVobjectType&gt;person&lt;\/MVobjectType&gt;\r\n      &lt;MVobjectType&gt;group&lt;\/MVobjectType&gt;\r\n      &lt;OU_USERS_INTERNAL&gt;OU=Internal,OU=Users,OU=MyOrg,DC=mydomain,DC=com&lt;\/OU_USERS_INTERNAL&gt;\r\n      &lt;OU_USERS_EXTERNAL&gt;OU=External,OU=Users,OU=MyOrg,DC=mydomain,DC=com&lt;\/OU_USERS_EXTERNAL&gt;\r\n      &lt;OU_USERS_GENERIC&gt;OU=Generic,OU=Users,OU=MyOrg,DC=mydomain,DC=com&lt;\/OU_USERS_GENERIC&gt;\r\n      &lt;OU_USERS_RESIGNED&gt;OU=Resigned,OU=Users,OU=MyOrg,DC=mydomain,DC=com&lt;\/OU_USERS_RESIGNED&gt;\r\n      &lt;OU_GROUPS&gt;OU=Groups,OU=MyOrg,DC=mydomain,DC=com&lt;\/OU_GROUPS&gt;\r\n      &lt;OU_CONTACTS&gt;OU=Contacts,OU=MyOrg,DC=mydomain,DC=com&lt;\/OU_CONTACTS&gt;\r\n    &lt;\/MA&gt;\r\n  &lt;\/ManagementAgents&gt;\r\n&lt;\/SyncParams&gt;<\/pre>\n<h3>Initialization<\/h3>\n<p>You can use the Initialization section of your extension code to open and load the XML lookup file. Note that you&#8217;ll have to do this in each extension project where you want to access parameters from the file. Your code will also need a reference to <strong>System.Xml<\/strong>.\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0<\/p>\n<pre>    Dim xmlParams As Xml.XmlDocument\r\n\r\n    Public Sub Initialize() Implements IMVSynchronization.Initialize\r\n        xmlParams = New Xml.XmlDocument\r\n        Dim xmlPath As String = Utils.ExtensionsDirectory &amp; \"\\SyncParams.xml\"\r\n\r\n        Try\r\n            xmlParams.Load(xmlPath)\r\n        Catch ex As Exception\r\n            Throw New ExtensionException(\"Failed while opening XML parameter file. \" &amp; ex.Message)\r\n        End Try\r\n    End Sub\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0<\/pre>\n<h3>Accessing the Global parameters<\/h3>\n<p>TheGlobal parameters are easy to get to because there&#8217;s only one node for them. So to retrieve the server name from the XML file above I&#8217;d just do this:\u00c2\u00a0\u00c2\u00a0<\/p>\n<pre>    xmlParams.SelectSingleNode(\"\/\/Global\/SyncService\/ServerName\").InnerText\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0<\/pre>\n<h3>Accessing a specific MA&#8217;s Parameters<\/h3>\n<p>The next thing you will probably want to do is access the values for a specifc MA. I&#8217;m using the &#8220;tag&#8221; attribute as a way to identitfy the correct node. In this example I\u00c2\u00a0retrieve an OU name from\u00c2\u00a0the\u00c2\u00a0&#8220;AD mydomain&#8221; parameters.\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0<\/p>\n<pre>    xmlParams.SelectSingleNode(\"\/\/ManagementAgents\/MA[@tag='MAName_AD']\/OU_USERS_EXTERNAL\").InnerText<\/pre>\n<h3>Creating a Hash Table of MA Names<\/h3>\n<p>The other thing that can be useful is to make a hash table of MA Names for easy reference. First you need to define a global variable:\u00c2\u00a0\u00c2\u00a0<\/p>\n<pre>    Dim MA_Names As New Collection<\/pre>\n<p>Then you add something like this to the Initialization sub:\u00c2\u00a0\u00c2\u00a0<\/p>\n<pre>    For Each xmlNode In xmlParams.SelectNodes(\"\/\/ManagementAgents\/MA\")\r\n        MA_Names.Add(xmlNode.Attributes(\"name\").Value, xmlNode.Attributes(\"tag\").Value)\r\n    Next<\/pre>\n<p>Now\u00c2\u00a0in the rest of the project, when you want to use an MA&#8217;s name, you only need refer to it using its tag:\u00c2\u00a0\u00c2\u00a0<\/p>\n<pre>    MA_Names.Item(\"MAName_AD\").ToString\u00c2\u00a0<\/pre>\n<h3>Selectively disabling provisioning<\/h3>\n<p>Another thing you might like to do, especially if you have a number of MAs that you are provisioning to, is to be able to selectively disable the provisioning code for one of them just by using the XML file.<\/p>\n<p>Obviously you&#8217;ll have to modify your provisioning code to check the value of the flag. In the example above I would need to\u00c2\u00a0test for the value of &#8220;provEnabled&#8221; before calling the provisioning code for the &#8220;AD mydomain&#8221; MA:<\/p>\n<pre>\r\n    If xmlParams.SelectSingleNode(\"\/\/ManagementAgents\/MA[@tag='MAName_AD']\/provEnabled\").InnerText = \"True\" then\r\n        Provision_AD(mventry)\r\n    End If<\/pre>\n<h3>Conclusion<\/h3>\n<p>Of course all of this takes more effort in the coding\u00c2\u00a0but the code will be more robust if it avoids hard-coded values, and it will be easier for others to make simple changes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On my first ever MIIS project we were an OCG customer so were able to use their nice XML library. I can&#8217;t remember in great detail what it did, but I&#8217;ve always considered the concept a best practise: if there&#8217;s anything that you find yourself hard-coding as a constant value in extension code, then you&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[42,34,28,30],"tags":[],"class_list":["post-1039","post","type-post","status-publish","format-standard","hentry","category-fim-2010","category-ilm2007","category-miis2003","category-vbnet"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pkp1o-gL","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1039","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/comments?post=1039"}],"version-history":[{"count":10,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1039\/revisions"}],"predecessor-version":[{"id":1050,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1039\/revisions\/1050"}],"wp:attachment":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/media?parent=1039"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/categories?post=1039"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/tags?post=1039"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}