Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

DNN Module Packager

4.61/5 (11 votes)
22 Nov 2006CPOL2 min read 1   1K  
A utility that creates a DotNetNuke manifest file and packages a module.

Sample Image - screen1.jpg

Introduction

The DNN Module Packager is a utility that creates a DotNetNuke manifest file and packages the module into a ZIP file for deployment to a DotNetNuke 3.x or DotNetNuke 4.x hosting site. You can edit the manifest file before packaging, and also add any other files to the package that your module needs to function properly in a DotNetNuke environment. The DNN manifest file is simply an XML file that contains information about the module, its DNN-interface controls (like View, Edit, and Settings controls), and a listing of all the folders, files, and binaries needed by the module.

Using the DNN Module Packager

The DNN Module Packager requires the basic .DNN manifest file that is automatically created by the DotNetNuke module templates in Visual Studio. If you don't have a .DNN manifest, you can always copy one from the DotNetNuke installation and modify it for your own module.

The basic steps for packaging a DNN module are:

  1. Select the .DNN manifest file.
  2. Select the root of the module directory.
  3. Select the target Zip output directory and filename.
  4. Generate the manifest (and perform edits to the manifest if needed).
  5. Add any other DLLs, code files, or other files needed in the package.
  6. Generate the package.

Another useful feature is the ability to automatically exclude any files that have particular extensions that reside in the module directory and its subdirectories that you don't want included in the manifest or the package (like VSS and other source-control files).

Below is a quick overview of the packaging process and the various screens/tabs in the DNN Module Packager:

Sample DNN Module Package with Additional Files

Template

Sample DNN Module Package Manifest

Generated

Results of the DNN Module Packaging

Generated

How the DNN Module Packager Works

The main engine/processor of the DNN Module Packager is the DnnGenerator class. Its primary function is to enumerate all the files under the module's root directory (and subdirectories) and add them to the DNN manifest as folder/file XML nodes. The DnnGenerator class also maintains a list of all the files in the package, and is responsible for assembling the final 'product': the zipped DNN module package.

C#
class DnnGenerator
{
    /// <summary>
    /// Generates a .DNN manifest file for a DNN Module project.
    /// Primarily, this is used to enumerate all the 
    /// filenames and paths in the project
    /// and put them in the .dnn manifest file properly

    /// </summary>
    /// <param name="sOldDnnFilePath">The original module DNN file</param>
    /// <param name="sProjectPath">Path to the DNN Module/files</param>
    /// <param name="aryOtherFiles">Array of binary files
    /// to include with the project</param>

    /// <returns></returns>

    public static string GenerateProjectDnnConfig(string sOldDnnFilePath, 
           string sProjectPath, string sExcludeExts, ArrayList aryOtherFiles)
    {
        string sNewDnnFile = string.Empty;

        if (File.Exists(sOldDnnFilePath) == false)
        {
            throw new Exception("Specified .DNN manifest file does not exist!");           
        }

        if (Directory.Exists(sProjectPath) == false)
        {
            throw new Exception("Specified DNN Module project path does not exist!");
        }

        // reads in default .dnn file

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(sOldDnnFilePath);

        // removes all the <files> elems

        XmlNode node = xmlDoc.SelectSingleNode("/dotnetnuke/folders/folder/files");
        node.RemoveAll();

        // get a list of all the files under the project path

        ArrayList aryFiles = FileUtilities.GetFilesInFolder(sProjectPath, true);

        // get the list of extensions to include

        string[] _ExcludeExts = sExcludeExts.Split(',');
        ArrayList aryExcludeExts = new ArrayList();
        foreach (string sExt in _ExcludeExts)
        {
            aryExcludeExts.Add(sExt.Trim().ToLower());
        }
        
        // regenerates the <files> elems with current file/relpath info

        foreach (string sfile in aryFiles)
        {
            FileInfo fi = new FileInfo(sfile);
            if (aryExcludeExts.Contains(fi.Extension.Trim().ToLower()) == true)
            {
                continue;
            }

            XmlElement xnfile = xmlDoc.CreateElement("file");
            node.AppendChild(xnfile);

            string srelpath = FileUtilities.RelativePathTo(sProjectPath, 
                                                           fi.DirectoryName);
            if (srelpath.Length > 0)
            {
                // relative path to project with no preceding slashes            

                XmlElement xnpath = xmlDoc.CreateElement("path");
                xnfile.AppendChild(xnpath);
                xnpath.InnerText = srelpath;

                // TEST:  need to check multiple Sub dirs with DNN

                // may need to change '\' to a '/' in path

            }                
            
            XmlElement xnname = xmlDoc.CreateElement("name");
            xnfile.AppendChild(xnname);
            xnname.InnerText = fi.Name;
        }

        // regenerates the <files> elems for any added assemblies 

        foreach (string sotherfile in aryOtherFiles)
        {
            FileInfo fi = new FileInfo(sotherfile);

            XmlElement xnfile = xmlDoc.CreateElement("file");
            node.AppendChild(xnfile);
            
            if (fi.FullName.ToUpper().IndexOf("\\APP_CODE\\") >= 0)
            {
                // relative path to project with no preceding slashes            
                XmlElement xnpath = xmlDoc.CreateElement("path");
                xnfile.AppendChild(xnpath);
                xnpath.InnerText = "[app_code]"; 
            }  

            XmlElement xnname = xmlDoc.CreateElement("name");
            xnfile.AppendChild(xnname);
            xnname.InnerText = fi.Name;
        }        
        
        return xmlDoc.InnerXml;
    }

    /// <summary>
    /// Backs-up the old DNN manifest and writes the specified contenst to a new DNN file
    /// </summary>
    /// <param name="sOldDnnFilePath"></param>
    /// <param name="sNewContents"></param>
    public static void SaveNewDnnConfigFile(string sOldDnnFilePath, string sNewContents)
    { 
        string sNewDnnFilePath = Path.GetTempFileName();
        FileUtilities.WriteFileContents(sNewDnnFilePath, sNewContents, true);

        // copy the existing dnn file to a backup file
        //if(File.Exists(sOldDnnFilePath + ".backup") == false)
        //{
          //  File.Copy(sOldDnnFilePath, sOldDnnFilePath + ".backup");
        //}

        File.Delete(sOldDnnFilePath);
        File.Move(sNewDnnFilePath, sOldDnnFilePath);            
    }

    /// <summary>
    /// Creates a DNN module package from the project path, other files, 
    /// and then stores it as a ZIP file
    /// </summary>
    /// <param name="sZipDestFile"></param>
    /// <param name="sProjectPath"></param>
    /// <param name="aryOtherFiles"></param>
    public static void GenerateDnnModulePackage(string sZipDestFile, 
           string sProjectPath, string sExcludeExts, ArrayList aryOtherFiles)
    { 
         // get a list of all the files under the project path
        ArrayList aryFiles = FileUtilities.GetFilesInFolder(sProjectPath, true);

        // add a list of other files to be included in bin dir (like dlls)
        aryFiles.AddRange(aryOtherFiles);

        // remove any files that have excluded extensions
        aryFiles = DnnGenerator.RemoveExcludedFiles(sExcludeExts, aryFiles);

        // zip everything up to where you save it to
        FileUtilities.ZipFiles(sZipDestFile, null, aryFiles);
    }

    /// <summary>
    /// Returns an arraylist of the files that have non-excluded extensions
    /// </summary>
    /// <param name="sExcludeExts"></param>
    /// <param name="aryOtherFiles"></param>
    /// <returns></returns>
    private static ArrayList RemoveExcludedFiles(string sExcludeExts, 
                                                 ArrayList aryOtherFiles)
    {
        ArrayList aryFiles = new ArrayList();
        ArrayList aryExcludeExts = new ArrayList();

        // get the list of extensions to include
        string[] _ExcludeExts = sExcludeExts.Split(',');
        foreach (string sExt in _ExcludeExts)
        {
            aryExcludeExts.Add(sExt.Trim().ToLower());
        }
        
        // only transfer the files with non-excluded extensions
        foreach (string sfile in aryOtherFiles)
        {
            FileInfo fi = new FileInfo(sfile);
            if (aryExcludeExts.Contains(fi.Extension.Trim().ToLower()) == true)
            {
                continue;
            }

            aryFiles.Add(sfile);
        }

        return aryFiles;
    }
}

Conclusion

I hope you find this article and utility useful - I've found it to make packaging and deploying DNN modules a snap!

License

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