Usman ur Rehman Ahmed's blog

Dependency section of a DNN manifest file

Dependencies Section

The dependencies section was introduced in the DNN’s manifest file with the new installation mechanism. Intending to support true extensions based deployment philosophy in DNN where one package may contain various different types of components.

Dependencies as the name suggest provide a check and validation for installation to continue. Different types of validations can be performed identified by the type attribute value in the dependency section as following,

      <dependencies>

        <dependency type="Type|CoreVersion|Package|Permission"></dependency>

      </dependencies>

Note: A manifest file with no dependencies is defined as following,

      <dependencies />

The dependency is usually found at following location in the manifest file,

Dependency
type=Type

Type is used to represent a class. Please note that fully qualified name of the class must be supplied. In type you can specify any class from any other module. For example to ensure that user defined table module is installed,

      <dependencies>

        <dependency type="Type">DotNetNuke.Modules.UserDefinedTable.UserDefinedTableController</dependency>

      </dependencies>

type=CoreVersion

CoreVesion specifies the minimum core version of DNN that must be present for the package to be installed. For example below snippet ensures that this package can be installed on sites running on top of DNN’s 05.05.01 version or above,

      <dependencies>

        <dependency type="CoreVersion">05.05.00</dependency>

      </dependencies>

type=Package

A type of Package refers to the check on name (not the friendly name) of the package that must be installed prior to installation of this module. For example, a rule like this would mean,

      <dependencies>

        <dependency type="Package">SampleModule</dependency>

      </dependencies>

 

That a package “SampleModule” is already installed with manifest file as following,

<dotnetnuke type="Package" version="5.0">

  <packages>

    <package name="SampleModule" type="Module" version="01.00.07">

      <friendlyName>A sample Module</friendlyName>

type=Permission

Permission type refers to the ability to specify the core .NET permission set required for this module to be operational. In case of installations on shared web hosting this is a great feature to be utilized. For example the dependency below,

      <dependencies>

        <dependency type="Permission">System.Web.AspNetHostingPermission</dependency>

      </dependencies>

ensures that the trust level of the executing DNN website application is higher enough to access protected ASP .NET classes. Examples include the use of classes encapsulated within System.Diagnostic namespace while your site is running with minimal trust level on a shared hosting.

Thus if your code does utilize such a class, having a dependency rule like above will help you protect your module customer’s websites going down by restricting module installation while also prompting a message giving insight why the installation couldn’t be carried out.

Most important types of permissions are exposed under System.Security.Permissions namespace like,

-         EnvironmentPermission

-          SecurityPermissions

For more information of permissions please take a look at,

http://msdn.microsoft.com/en-us/library/system.security.permissions.aspx

Mixing Dependency Types

It is possible to mix different dependencies together to make up a strict validation rule to be met for installation to continue. This may be required in some cases. An example is to install a module that requires SSL powered DNN (which was in 5.4.0 I believe) and a custom module (FileTransferModule) be installed,

      <dependencies>

        <dependency type="CoreVersion">05.04.00</dependency>

        <dependency type="Package">FileTransferModule</dependency>

      </dependencies>

Check whether given database object exists in the DNN installation scripts

Following are the ways I have been using to check for existance of various database object types in the DNN installation/uninsatllation scripts. In each script <ObjectName> needs to be replaced with the actual database object (table, stored procedure, etc...) name

Check if Table Exists?

    IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<TableName>]') AND type in (N'U'))

Check if Stored Procedure Exists?

    IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<StoredProcedureName>]') AND type in (N'P', N'PC'))

Check if Function Exists?

    IF  EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<FunctionName>]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))

Check if Foriegn Key Exists?

    IF  EXISTS (SELECT 1 FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<ForeignKeyName>]') AND parent_object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<TableName>]'))

How to manipulate web.config file programatically?

DNN provides robust mehcnaism for taking care of configuration chagnes in web.config file by means of config type componetns in the manifest file but they can be dangerous as a slight mistake can bring down the whole web site and second, it doesn't provide option switches to make entries based over conditions. Such conditional entry is required just as the case with IIS7 integrated mode.

Up untill IIS6, the section <httpModules> was enough for an http module to be executed rightly but with the launch of IIS7, an entry of http module is required within <modules> section as well if IIS7 with running integrated mode.

The method shared below takes care of integrated mode and can be used if such configuration change is required based over user interaction. That is, the design of module or provider be updated in a way that user interaction is required to enable/disable an entry.

        public static bool AddHttpModuleEntry(string name, string type)
        {
            try
            {
                XmlDocument document = new XmlDocument();
                document.Load(HttpContext.Current.Server.MapPath("~/web.config"));
                bool nodeFound = false;
                XmlNodeList nodes;
                bool toSave = false;

                //For IIS6 or IIS7 (normal mode)
                nodes = document.SelectNodes("/configuration/system.web/httpModules/add");
                if (nodes != null)
                {
                    //Look for the desired node
                    foreach (XmlNode node in nodes)
                    {
                        if (node.Attributes["name"].Value == name)
                        {
                            nodeFound = true;
                        }
                    }
                    if (!nodeFound)
                    {
                        //Required node doesn't exist, add it
                        XmlNode node = document.CreateElement("add");
                        XmlAttribute nameAttribute = document.CreateAttribute("name");
                        nameAttribute.Value = name;
                        XmlAttribute typeAttribute = document.CreateAttribute("type");
                        typeAttribute.Value = type;
                        node.Attributes.Append(nameAttribute);
                        node.Attributes.Append(typeAttribute);
                        nodes[0].ParentNode.AppendChild(node);
                        toSave = true;
                    }
                }


                //For IIS7 (integrated mode)
                nodeFound = false;
                if (HttpRuntime.UsingIntegratedPipeline)
                {
                    //Add an entry in the system.webServer section (this is specific to IIS7 integrated mode)
                    nodes = document.SelectNodes("/configuration/system.webServer/modules/add");
                    if (nodes != null)
                    {
                        //Look for the desired node
                        foreach (XmlNode node in nodes)
                        {
                            if (node.Attributes["name"].Value == name)
                            {
                                nodeFound = true;
                            }
                        }
                        if (!nodeFound)
                        {
                            //Required node doesn't exist, add it
                            XmlNode node = document.CreateElement("add");
                            XmlAttribute nameAttribute = document.CreateAttribute("name");
                            XmlAttribute typeAttribute = document.CreateAttribute("type");
                            XmlAttribute preConditionAttribute = document.CreateAttribute("preCondition");

                            nameAttribute.Value = name;
                            typeAttribute.Value = type;
                            preConditionAttribute.Value = "managedHandler";

                            node.Attributes.Append(nameAttribute);
                            node.Attributes.Append(typeAttribute);
                            node.Attributes.Append(preConditionAttribute);
                            nodes[0].ParentNode.AppendChild(node);

                            toSave = true;
                        }
                    }
                }

                if (toSave)
                {
                    document.Save(HttpContext.Current.Server.MapPath("~/web.config"));
                }
                return true;
            }
            catch {
                throw;
            }
        }

Similar approach can be used to make changes (add/edit/delete) for any given section in any configuration (mostly web.config) file.

12
To Posterous, Love Metalab