Click here to Skip to main content
15,895,777 members
Articles / Programming Languages / C#

Collision Finder

Rate me:
Please Sign up or sign in to vote.
4.67/5 (10 votes)
12 Jul 2006CPOL1 min read 27.4K   629   15  
A tool that finds refernced DLL version collisions.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Xml;
using System.Data;

namespace FindReferenceCollisions
{
    public class FindCollisions
    {
        #region members
        //dataset where all the dll references  data is saved in
        private ReferenceCollisionDataSet _ds = new ReferenceCollisionDataSet();
        //all the app.config versions data is saved in
        private List<AppRefVersion> _appList = new List<AppRefVersion>();
        // the message for printing
        private StringBuilder _Collisions = new StringBuilder();
        #endregion

        #region public methods
        //return false if there is any collision or problem
        public bool Find(string directory)
        {
            _ds.Clear();
            _appList.Clear();
            if (!System.IO.Directory.Exists(directory))
            {
                _Collisions.AppendLine("Directory not found");
                return false;
            }
            //get all the file names from the directory
            string[] files = System.IO.Directory.GetFiles(directory);
            foreach (string file in files)
            {
                //check if i can reflect this file
                if (CanReflected(file))
                {
                    //if the file is app.config 
                    //i take all the collisions data 
                    if (file.IndexOf(".config") != -1)
                        AnalysisAppConfig(file);
                    else
                        //reflect all the dotnet dll and exe files 
                        //and get all there references and insert them into dataset 
                        FillDataSet(file);
                }
            }
            //Find all the collisions
            //and insert them into data set and into string
            return FindCollisons();
        }
        #endregion

        #region private methods
        //check if i can reflect this file
        private bool CanReflected(string file)
        {
            if ((file.IndexOf(".dll") != -1 || file.IndexOf(".exe") != -1) &&
                    (file.IndexOf("mscorlib.dll") == -1 &&
                    !file.Trim().StartsWith("System.") &&
                     file.Trim().IndexOf(".vshost.exe") == -1))
            {
                return true;
            }
            return false;
        }
        //check if this reference is not a system reference
        private bool IsNotSystemRef(AssemblyName refName)
        {
            if (refName.Name.IndexOf("mscorlib") == -1 &&
                           !refName.Name.Trim().StartsWith("system") &&
                           !refName.Name.Trim().StartsWith("System"))
            {
                return true;
            }
            return false;
        }
        //reflect all the dotnet dll and exe files 
        //and get all there references and insert them into dataset 
        private void FillDataSet(string file)
        {
            try
            {
                ReferenceCollisionDataSet.DllTableRow dllRow = _ds.DllTable.NewDllTableRow();
                Assembly asm = Assembly.LoadFile(file);
                AssemblyName asmName = asm.GetName();
                dllRow.Name = asmName.Name;
                dllRow.Version = asmName.Version.ToString();
                _ds.DllTable.Rows.Add(dllRow);
                //run on all the references of the curent Assembly
                foreach (AssemblyName refName in asm.GetReferencedAssemblies())
                {
                    try
                    {
                        //check if this reference is not a system reference
                        if (IsNotSystemRef(refName))
                        {
                            ReferenceCollisionDataSet.ReferenceTableRow refRow = _ds.ReferenceTable.NewReferenceTableRow();
                            refRow.Dll_Name = asmName.Name;
                            refRow.Reference_Name = refName.Name;
                            refRow.Version = refName.Version.ToString();
                            _ds.ReferenceTable.Rows.Add(refRow);
                        }
                    }
                    catch
                    {
                    }
                }
            }
            catch { }


        }
        //this method take the collision data out of the App.config
        //using Xpath
        private void AnalysisAppConfig(string exeFile)
        {

            if (File.Exists(exeFile))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(exeFile);
                XmlNode node = doc.FirstChild;
                //find all the nodes with Xpath ="/configuration/runtime"
                XmlNodeList nodeList = doc.SelectNodes("/configuration/runtime");
                if (nodeList != null && nodeList.Count > 0)
                {
                    foreach (XmlNode singleNode in nodeList)
                    {
                        if (singleNode.FirstChild != null)
                        {
                            foreach (XmlNode childNode in singleNode.FirstChild.ChildNodes)
                            {
                                XmlNode node1 = childNode.FirstChild;
                                XmlAttribute xmlAttributeName = node1.Attributes["name"];
                                XmlNode node2 = childNode.ChildNodes[1];
                                XmlAttribute xmlAttributeVersion = node2.Attributes["oldVersion"];
                                //insert all the data into the array of AppRefVersion
                                if (xmlAttributeVersion != null && xmlAttributeName != null)
                                    _appList.Add(new AppRefVersion(xmlAttributeName.Value, xmlAttributeVersion.Value));
                            }
                        }
                    }

                }

            }
        }
        //this method run on all the data in ReferenceTable
        //and get all the collisions 
        private bool FindCollisons()
        {
            foreach (ReferenceCollisionDataSet.ReferenceTableRow refRow in _ds.ReferenceTable.Rows)
            {
                ReferenceCollisionDataSet.ParentRefTableRow[] refParent = (ReferenceCollisionDataSet.ParentRefTableRow[])
                    _ds.ParentRefTable.Select(string.Format("Reference_Name='{0}' AND Version='{1}'", refRow.Reference_Name, refRow.Version));
                bool IsInclude = false;
                if (_appList != null)
                {
                    //check if the version is between the what is write  in the app.config
                    foreach (AppRefVersion appRefVersion in _appList)
                    {
                        IsInclude = appRefVersion.IsInVersion(refRow.Version, refRow.Reference_Name) | IsInclude;
                    }
                }
                if (!IsInclude)
                {
                    if (refParent.Length > 0)
                    {
                        refParent[0].Count = refParent[0].Count + 1;
                    }
                    else
                    {
                        ReferenceCollisionDataSet.ParentRefTableRow newParentRow = _ds.ParentRefTable.NewParentRefTableRow();
                        newParentRow.Count = 1;
                        newParentRow.Version = refRow.Version;
                        newParentRow.Reference_Name = refRow.Reference_Name;
                        _ds.ParentRefTable.Rows.Add(newParentRow);
                    }
                    ReferenceCollisionDataSet.ChildRefTableRow newChildRow = _ds.ChildRefTable.NewChildRefTableRow();
                    newChildRow.Version = refRow.Version;
                    newChildRow.Reference_Name = refRow.Reference_Name;
                    newChildRow.Dll_Name = refRow.Dll_Name;
                    _ds.ChildRefTable.Rows.Add(newChildRow);
                }
            }
            //delete all the Unnecessary Rows
            DeleteUnnecessaryRows();
            //write the collisions information into string
            return WriteTostring();
        }
        //delete all the Unnecessary Rows like all the rows that dosent have collision 
        // and all the row that have only one reference
        private void DeleteUnnecessaryRows()
        {
            List<DataRow> rowDelete = new List<DataRow>();

            foreach (ReferenceCollisionDataSet.ParentRefTableRow refRow in _ds.ParentRefTable.Rows)
            {
                ReferenceCollisionDataSet.ParentRefTableRow[] refParent = (ReferenceCollisionDataSet.ParentRefTableRow[])
                    _ds.ParentRefTable.Select(string.Format("Reference_Name='{0}'", refRow.Reference_Name));
                if (refParent.Length <= 1)
                {
                    rowDelete.Add(refRow);
                }
            }
            
            foreach (ReferenceCollisionDataSet.ParentRefTableRow parentRow in _ds.ParentRefTable.Rows)
            {
                DataRow[] rows = parentRow.GetChildRows("ParentRefTable_ChildRefTable");
                if (rows.Length == 0)
                    rowDelete.Add(parentRow);
            }
            foreach (DataRow row in rowDelete)
            {
                row.Delete();
            }
        }
        //write the collisions information into string
        private bool WriteTostring()
        {
            //check if we use information from the app.config
            if (_appList.Count > 0)
            {
                _Collisions.AppendLine(string.Format("Use App.config to cancel collisions "));
            }
            //check if there is  any collisions at all
            if (_ds.ParentRefTable.Rows.Count > 0)
            {
                 List<string> referenceNames = new List<string>();
                _Collisions.AppendLine(string.Format("Have version collision :"));
                foreach (ReferenceCollisionDataSet.ParentRefTableRow pRow in _ds.ParentRefTable.Rows)
                {
                    if (!referenceNames.Contains(pRow.Reference_Name))
                    {
                        _Collisions.AppendLine("--------------------------------------------------------------");
                         _Collisions.AppendLine(string.Format("Reference name : {0}", pRow.Reference_Name));
                         _Collisions.AppendLine("--------------------------------------------------------------");
                        foreach (ReferenceCollisionDataSet.ChildRefTableRow cRow in
                            (ReferenceCollisionDataSet.ChildRefTableRow[])_ds.ChildRefTable.Select(string.Format("Reference_Name='{0}'", pRow.Reference_Name)))
                        {
                             _Collisions.AppendLine(string.Format("Dll name : {0} Version : {1}", cRow.Dll_Name, cRow.Version));
                        }
                    }
                    referenceNames.Add(pRow.Reference_Name);
                }

            }
            if (_ds.ParentRefTable.Rows.Count > 0)
                return false;
            return true;
        }
        #endregion

        #region properties
        public string CollisionsOutPut
        {
            get
            {
                return _Collisions.ToString();
            }
        }
        public ReferenceCollisionDataSet Data
        {
            get
            {
                return _ds;
            }
        }
        #endregion
    }

    internal class AppRefVersion
    {
        public Version _startVersion = null;
        public Version _endVersion = null;
        public string _ref = string.Empty;
        public AppRefVersion(string reference, string version)
        {
            InsertRefVersion(reference, version);
        }
        public string Reference
        {
            get
            {
                return _ref;
            }
        }
        //chack if the refernce  is similar and the virsion is between 
        // the virsion of the app.config
        public bool IsInVersion(string version, string reference)
        {
            Version newVersion = new Version(version);
            if (_startVersion.CompareTo(newVersion) <= 0 &&
                _endVersion.CompareTo(newVersion) >= 0 &&
                _ref.Trim() == reference.Trim())
                return true;
            return false;
        }
        private void InsertRefVersion(string reference, string version)
        {
            try
            {
                string[] Split = version.Split('-');
                _startVersion = new Version(Split[0]);
                _endVersion = new Version(Split[1]);
                _ref = reference;
            }
            catch
            {
            }
        }

    }

   
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions