(formerly posted at http://blogs.technet.com/shawnrab/archive/2007/06/28/xml-based-miis-ilm-metaverse-router-part-1.aspx ) 

So one of the complaints of people who use MIIS/IIFP/ILM for GALSync is that there is only one field for a metaverse rules extension.  If you wanted to add provisioning in addition and seperate from the logic in the provision() block in the GALSync DLL, you would have to extend the GALSync.vb code which is subject to change (and be replaced in cumulative updates and service packs). There is decent solution out there called the MVRouter which looks in the MIIS extensions directory and looks for any DLL that starts with "mv" or "MVExtension" in the Extensions directory underneath the MIIS installation folder(technically it has a global called PREFIX that you can set).  It will call MV_Galsync.Provision() or MV_Extension.Provision() within MVRouter.Provision() if your PREFIX is "MV_".  The sample is located at the MIIS developer reference  (http://msdn2.microsoft.com/en-us/library/ms698364.aspx) and more targeted at http://msdn2.microsoft.com/en-us/library/ms696018.aspx

In sporadic posts, including this one we will build upon the sample at http://msdn2.microsoft.com/en-us/library/ms696018.aspx to create an XML-based MVRouter and we will use that to try some fairly cool things with MIIS.

I warn all of you.  This is just a sample.  We're going to grow this sample as time passes.  Also, suggestions are always appreciated.  There will always be a better way to write code. 

 

----snip----


using
System;
using Microsoft.MetadirectoryServices;
using System.Xml;

namespace
Miis_Metaverse
{
    public class MVExtensionObject : IMVSynchronization
    {
        IMVSynchronization[] myMVDlls;
//global array to pop the Metaverse Sync objects
        string[] MVsToRun; //global array for string literal DLL's
        XmlDocument doc = new XmlDocument(); //global XML document - we may want to bring this local later


        void IMVSynchronization.Initialize()
        {

            //the variable "dlls" is a number resulting from the private function popInitializeArr which will grab the 
            //metaverse dll files from the XML file
            short dlls = popInitializeArr();

 

            // Create the array the size of the number of files we found.
            myMVDlls = new IMVSynchronization[dlls];
            string fileName; // local variable for the file name
            Assembly assem; //local variable to use to load the DLL 
            Type[] types; //local variable array to get type declarations from the DLL
            Object objLoaded = null;

            // Load the extension files into the array.
           for(int i = 0; i < dlls; i++) //run this for the number of dll's that we have.

            //We could simplify and do a foreach if we wanted to 
            //ex: foreach (string mvtorun in mvstorun)
            {

                // Load the assembly.
                fileName = MVsToRun[i];

                assem = Assembly.LoadFrom(Utils.ExtensionsDirectory +
@"\" + fileName); //this checks for the file name/presence
 

                //note: we don't check to ensure that it is a DLL file here - a definite future improvement, not do we handle the 
                //lack of presence - we're assuming the file stated in XML actually exists
                types = assem.GetExportedTypes();

                foreach (Type type in types)
                {
                    if (type.GetInterface("Microsoft.MetadirectoryServices.IMVSynchronization") != null)
                    {

                       // Create an instance of the MV extension object type.
                        objLoaded = assem.CreateInstance(type.FullName);
                        break;

                    }

                }
//end foreach
 

                // If an object type within could not be found,
                // or if an instance could not be created, throw an exception.

                if (null == objLoaded)
                {

                    throw new UnexpectedDataException("Object type not found or instance not created");

                }
                // Add this MV extension object to our array of objects.
                myMVDlls[i] = (IMVSynchronization)objLoaded;

                // Call the Initialize() method on each MV extension object.
                myMVDlls[i].Initialize();

            }
        }

        

 

 

        void IMVSynchronization.Terminate()
        {

            // Call the Terminate() method on each MV extension object.
            foreach (IMVSynchronization mvextension in myMVDlls)
            {

                mvextension.Terminate();

            }

        }

 

 

        void IMVSynchronization.Provision(MVEntry mventry)
        {
            // Call the Provision() method on each MV extension object.
            foreach (IMVSynchronization mvextension in myMVDlls)
            {

                mvextension.Provision(mventry);

            }

        }

        

 

 

        bool IMVSynchronization.ShouldDeleteFromMV(CSEntry csentry, MVEntry mventry)
        {

            bool shouldDelete = false;
            // Call the ShouldDeleteFromMV() method on each MV extension object.
            foreach (IMVSynchronization mvextension in myMVDlls)
            {

                if (mvextension.ShouldDeleteFromMV(csentry, mventry))
                {

                    shouldDelete =
true;
                    break;

                }// end if
            }// end for
            return (shouldDelete);

        }

        

 

 

        /* popInitializeArr is a function created to populate a DLL array and return a number exemplifying the number of dll's in the array*/
        private short popInitializeArr()
        {

            short numParticipatingDLLs;
            numParticipatingDLLs = 0;
//assume nothing is there


            //logic to dig in XML to find the number of participating dlls
            doc.Load(Utils.ExtensionsDirectory + @"\MIISXML.xml"); //Utils.ExtensionsDirectory grabs the Extensions folder under the 
            //MIIS install folder



            XmlNode node = doc.SelectSingleNode(
"rules-extension-properties/dllfiles");


            //so the base tag is <rules-extension-properties> and we have a single child <dllfiles> - we are initializing 
            //variable "node" as <dllfiles>
            if (node.HasChildNodes) //I love expressions that do what they say
            {

                //right off the bat let's assume that the child nodes all correspond to dll file names
                //we'll do some checks in making this code better that ensure the DLL is present

                numParticipatingDLLs = (
short)node.ChildNodes.Count;
                //initialize the str array with the number we're running - we can concat later
                MVsToRun = new String[numParticipatingDLLs];
                //and we'll whittle it down and 
                int index = 0;

                foreach (XmlNode child in node.ChildNodes)
                {

                    //we probably need to check for the text ".dll" or append it later /check for indexOf ".dll" later...
                    MVsToRun.SetValue(child.Name, index);
                    index++;

                }
//end foreach

            }
// end if


  



            return numParticipatingDLLs;

        }
// end popInitializeArr

    }
//end class

}
//end namespace


 

----end snip----

 

So our requirements need to be that the file name has to correspond exactly with the XML tag and must exist in the extensions directory.  We should probably fix that later.  We also have some other homework to do and I have ideas to show the potential of this thing. 

Right now the XML tagging would look like this:

 

---snip----

<rules-extension-properties>

    <dllfiles>

        <examplemvdllname.dll></examplemvdllname.dll>

        <samplemvdllname2.dll></samplemvdllname2.dll>

        ...

    </dllfiles>

</rules-extension-properties>

----end snip----

 

Think about the potential here - we could use the tags and innertext to our advantage.  In the future, I will show some optimization I think we need and if anyone adds insight, I can add that.  Also I have an advancement that I want to put in place that may (or may not) work. 

 

--Shawn

 

 

 

 

This posting is provided "AS IS" with no warranties, and confers no rights.

And Just in case...

This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment. THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute the object code form of the Sample Code, provided that You agree: (i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded; (ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys’ fees, that arise or result from the use or distribution of the Sample Code.