XML Lookup file

On my first ever MIIS project we were an OCG customer so were able to use their nice XML library. I can’t remember in great detail what it did, but I’ve always considered the concept a best practise: if there’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.

I’ve been working on a couple of projects this year which are big and complicated enough to warrant a proper lookup file, so I’ve finally had to get in and figure out how to parse XML in .NET. As usual this post is just about things I’ve been doing and I’m not trying to say this is the best way to go. You will have to adapt to your own requirements.    

The Structure of the XML File

The general outline of my XML file is to have a section for Global settings, and then individual sections for each MA. Note the “tag” for each MA, which I’ll be using in the code.  The specifc values you include for each MA are entirely up to your requirements.

<SyncParams>
  <Global>
    <SyncService>
      <ServerName>mysyncserver.mydomain.com</ServerName>
      <IsDev>False</IsDev>
    </SyncService>
    <SQL>
      <Server>mysqlserver.mydomain.com</Server>
    </SQL>
  </Global>
  <ManagementAgents>
    <MA name='FIM Portal' tag='MAName_FIM'>
      <maType>FIM</maType>
      <MVobjectType>person</MVobjectType>
      <MVobjectType>group</MVobjectType>
      <MVobjectSource>group</MVobjectSource>
    </MA>
    <MA name='SQL HR Employees' tag='MAName_HR'>
      <maType>SQL</maType>
      <MVobjectType>person</MVobjectType>
      <MVobjectSource>person</MVobjectSource>
    </MA>
    <MA name='Notes' tag='MAName_Notes'>
      <maType>NOTES</maType>
      <MVobjectType>person</MVobjectType>
      <MVobjectSource>person</MVobjectSource>
    </MA>
    <MA name='AD mydomain' tag='MAName_AD'>
      <maType>AD</maType>
      <provEnabled>True</provEnabled>
      <MVobjectType>person</MVobjectType>
      <MVobjectType>group</MVobjectType>
      <OU_USERS_INTERNAL>OU=Internal,OU=Users,OU=MyOrg,DC=mydomain,DC=com</OU_USERS_INTERNAL>
      <OU_USERS_EXTERNAL>OU=External,OU=Users,OU=MyOrg,DC=mydomain,DC=com</OU_USERS_EXTERNAL>
      <OU_USERS_GENERIC>OU=Generic,OU=Users,OU=MyOrg,DC=mydomain,DC=com</OU_USERS_GENERIC>
      <OU_USERS_RESIGNED>OU=Resigned,OU=Users,OU=MyOrg,DC=mydomain,DC=com</OU_USERS_RESIGNED>
      <OU_GROUPS>OU=Groups,OU=MyOrg,DC=mydomain,DC=com</OU_GROUPS>
      <OU_CONTACTS>OU=Contacts,OU=MyOrg,DC=mydomain,DC=com</OU_CONTACTS>
    </MA>
  </ManagementAgents>
</SyncParams>

Initialization

You can use the Initialization section of your extension code to open and load the XML lookup file. Note that you’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 System.Xml.    

    Dim xmlParams As Xml.XmlDocument

    Public Sub Initialize() Implements IMVSynchronization.Initialize
        xmlParams = New Xml.XmlDocument
        Dim xmlPath As String = Utils.ExtensionsDirectory & "\SyncParams.xml"

        Try
            xmlParams.Load(xmlPath)
        Catch ex As Exception
            Throw New ExtensionException("Failed while opening XML parameter file. " & ex.Message)
        End Try
    End Sub    

Accessing the Global parameters

TheGlobal parameters are easy to get to because there’s only one node for them. So to retrieve the server name from the XML file above I’d just do this:  

    xmlParams.SelectSingleNode("//Global/SyncService/ServerName").InnerText   

Accessing a specific MA’s Parameters

The next thing you will probably want to do is access the values for a specifc MA. I’m using the “tag” attribute as a way to identitfy the correct node. In this example I retrieve an OU name from the “AD mydomain” parameters.   

    xmlParams.SelectSingleNode("//ManagementAgents/MA[@tag='MAName_AD']/OU_USERS_EXTERNAL").InnerText

Creating a Hash Table of MA Names

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:  

    Dim MA_Names As New Collection

Then you add something like this to the Initialization sub:  

    For Each xmlNode In xmlParams.SelectNodes("//ManagementAgents/MA")
        MA_Names.Add(xmlNode.Attributes("name").Value, xmlNode.Attributes("tag").Value)
    Next

Now in the rest of the project, when you want to use an MA’s name, you only need refer to it using its tag:  

    MA_Names.Item("MAName_AD").ToString 

Selectively disabling provisioning

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.

Obviously you’ll have to modify your provisioning code to check the value of the flag. In the example above I would need to test for the value of “provEnabled” before calling the provisioning code for the “AD mydomain” MA:

    If xmlParams.SelectSingleNode("//ManagementAgents/MA[@tag='MAName_AD']/provEnabled").InnerText = "True" then
        Provision_AD(mventry)
    End If

Conclusion

Of course all of this takes more effort in the coding but the code will be more robust if it avoids hard-coded values, and it will be easier for others to make simple changes.

2 Replies to “XML Lookup file”

  1. Be careful with not guarding the SelectSingleNode calls – if the XPath expression doesn’t return anthing, accessing InnerText will throw a NullReferenceException which may be less than ideal depending on where you are calling it.

    I usually have a generic GetConfigEntry type method which takes a defaultValue parameter to return if nothing is configured.

    Also btw – inside System.IO is a class called Path – rather than concatenating strings together (and hoping you have all your slahes in order), Path.Combine will do it all for you. 🙂

  2. OK thanks, I’ll have a look at Path.Combine – I’m just learning this stuff.

    Yes I do a lot more error checking in my code, but it makes for a very long blog post 🙂

Comments are closed.