Meaning “IsPublic” for DotNetNuke Roles.

DotNetNuke Roles have “IsPublic” attribute. I wandered what the business meaning of the value. After reading the 4.0.2 code my understanding that if IsPublic=true, user is able to subscribe to the role, if it is free (see DotNetNukeadminSecurityRegister.ascx.vb).
I didn’t find any more business logic coded.
It seems that even if public=false, role is visible to user and even available for payed subscription.
(I haven’t tested it yet.)


Lazy roles Synchronization in DotNetNuke.

There is a thread: Role SynchronizationMode that asked what the meaning of the parameter in core AddRole method.
I investigated ability to syncronize roles from custom database to DNN and can post answer for this question(according to 4.0.2 core).

Parameter SynchronizationMode is used to implement “lazy” synchronization for roles.

If new role has been added to AspNet_Roles DNN calls synchronization to update satellite dnn_Roles table.


Parameter SynchronizationMode is used in RoleController.AddRole to indicate whether the role should be added to both the AspNet_Roles and dnn_Roles(SynchronizationMode=false) or to dnn_Roles only (SynchronizationMode=true).

The common use is to call AddRole(ByVal objRoleInfo As RoleInfo) overload, which corresponds to SynchronizationMode=false.


The call stack for syncronization (SynchronizationMode=true )is the following:

DotNetNukeadminSecurityRoles.ascx.vb: BindData ->

RoleController.GetPortalRoles(PortalId, True)->


objRoleController.AddRole(objRoleInfo, True)


There is also method

RoleController.GetRoleByName(ByVal PortalId As Integer, ByVal RoleName As String, ByVal SynchronizeRoles As Boolean) that also can be called to synchronize roles,  

but I didn’t find that is is called from anywhere with SynchronizeRoles=true.


WebResource Script in VBeXpressWebForms

My application still using VbExpress generated code even if the authors do not do any development/support.

When moving to DNN with URL rewriting I had to modify  VBeXpressWebForms.VBeXpressDatePicker.vb .

I’ve commented out in GenerateJScript

‘mnf 26/5/2006 strOut = strOut & “” & vbCrLf

Added <Assembly: WebResource(“Calendar.js”, “application/x-javascript”)> ,

added the “Calendar.js“ file as embedded resource and added

        Private Sub VBeXpressDatePicker_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim sResName As String = “Calendar.js”
            Debug.Assert(Not (Me.GetType().Assembly.GetManifestResourceInfo(sResName) Is Nothing))
            Me.Page.ClientScript.RegisterClientScriptResource(Me.GetType(), sResName)

        End Sub
See also my post about extra validation to make debugging of WebResources easier.

Check that embedded resource exist before calling ClientScript.RegisterClientScriptResource or GetWebResourceUrl

The Asp.NET 2.0 allows to provide JS files in embedded resources using WebResource.axd.

The procedure is well described here and here. Note that adding [assembly: WebResourceAttribute] attibute is important.

However  the methods ClientScript.RegisterClientScriptResource and ClientScript.GetWebResourceUrl do not throw exceptions, if embedded resource  is missing. They just generate invalid urls that can’t be visually checked because parameters are encrypted.
For easier identification of the error it is a good practice to check existence of resource prior to call using Debug.Assert or throw exception.

Type rstype = typeof(ClassInAssemblyWithResource);
Debug.Assert(null != rstype.Assembly.GetManifestResourceInfo(sFullName));
return page.ClientScript.GetWebResourceUrl(rstype, sFullName);

OR better way
StreamHelper.EnsureWebResourceValid(sFullName, rsType.Assembly,true)
page.ClientScript.RegisterClientScriptResource(rsType, FileName)

where EnsureWebResourceValid is the  function shown below.

Update: Jon in comments pointed about potential performance penalties.
To avoid it, call the function in Debug mode only,e.g.
Debug.Assert(StreamHelper.EnsureWebResourceValid(sFullName, rsType.Assembly,true));

        public static bool EnsureWebResourceValid(string ResName, Assembly Asm,bool ThrowException)


            bool bRet = StreamHelper.EnsureManifestResourceExist(ResName, Asm, ThrowException);


            { //find the attribute

                bRet = false;

                // Iterate through the attributes for the assembly.

                foreach (Attribute attr in Attribute.GetCustomAttributes(Asm))


                    //Check for WebResource attributes.

                    if (attr.GetType() == typeof(WebResourceAttribute))


                        WebResourceAttribute wra = (WebResourceAttribute)attr;

                        Debug.WriteLine (“Resource in the assembly: “ + wra.WebResource.ToString() +

                          ” with ContentType = “ + wra.ContentType.ToString() +

                          ” and PerformsSubstitution = “ + wra.PerformSubstitution.ToString() );

                        if (wra.WebResource== ResName)


                            bRet = true;





            } //ManifestResourceExist



                string sMsg=“Embedded resource “ + ResName + ” in assembly “ + Asm.FullName + ” doesn’t have WebResourceAttribute “;

                if (ThrowException == true)


                   throw new ApplicationException(sMsg);




                    Debug.Assert(false, sMsg);



            return bRet;


        //’if ThrowException=true, then Throw exception if resource not found

        public static bool EnsureManifestResourceExist(string ResName, Assembly Asm, bool ThrowException)

        {   //NOTE: If resource is located in subfolder of C# project, path of subfolder should be specified (it is included as part of namespace)

            //’ Resources are named using a fully qualified name ((including namespace).

            bool bRet=true;  

            ManifestResourceInfo info = Asm.GetManifestResourceInfo(ResName);

            if (info == null)



                string sMsg = “Couldn’t find embedded resource “ + ResName + ” in assembly “ + Asm.FullName;

                if (ThrowException)


                    throw new ApplicationException(sMsg);




                    Debug.Assert(false, sMsg);



            return bRet;




 I’ve submitted a suggestion to MS.

Programmatically set IIS Authentication for a page.

To use Mixed Windows Authentication one of the step is to set set authentication on one page only to be Windows Integrated, but not “allow anonymous”.(see instructions here and here).
I wanted to do it from Web Setup Project. So I’ve created the class IISMetaDataHelper with the method SetIntegratedSecurityOnly
Sample of the call is
 IISMetaDataHelper.SetIntegratedSecurityOnly(Site, VDir, “Admin/Security/WinLogin.aspx”)

Notice that .Net framework doesn’t have classes to handle IISMetaData properties and enum for AuthFlags property value. I’ve created those helper types as well.

Update: it is recommended to call folderRoot.RefreshCache() to make EVERYTHING work

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text;

using System.Xml;

using System.DirectoryServices;

using System.Diagnostics;

using System.IO;

using System.Reflection;

//using FSHelperLib;

namespace FSCSharpLib.IISMetadata


    /// <summary>

    //see also IISChameleon.INETMGRHelper

    /// Helper methods to access IIS Virtual directories

    /// </summary>

    /// <remarks>Code samples used are from ASP.NET IIS Chameleon Tool( and

    /// Creating Virtuals and reading Installed Sites on IIS with .Net( )    </remarks>

    public class IISMetaDataHelper


        //For debugginh it is convinient to use adsutil.vbs

        /*e.g commands

        C:InetpubAdminScriptsCscript.exe adsutil.vbs ENUM  W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        C:InetpubAdminScriptsCscript.exe adsutil.vbs CREATE  W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        C:InetpubAdminScriptsCscript.exe adsutil.vbs SET W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx/keyType IISWebFile

        C:InetpubAdminScriptsCscript.exe adsutil.vbs delete  W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx


        /// <summary>

        /// Concat parts of the path using Site Path in format @”/LM/W3SVC/1″ passed by Web Setup to path accepted by DirectoryEntry

        /// </summary>

        /// <param name=”SiteMetaPath”>Format @”/LM/W3SVC/1″</param>

        /// <param name=”VDirRoot”>e.g vKnowledge</param>

        /// <param name=”relPath”>e.g @”admin/Security/WinLogin.aspx”</param>

        /// <returns>e.g IIS://localhost/W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx</returns>

        public static void SetIntegratedSecurityOnly(string SiteMetaPath, String VDirRoot, String relPath)


            string MetabasePath = IISMetaPath(SiteMetaPath, VDirRoot, relPath);



        /// <summary>

        /// Concat parts of the path using Site Path in format @”/LM/W3SVC/1″ passed by Web Setup to path accepted by DirectoryEntry

        /// </summary>

        /// <param name=”SiteMetaPath”>Format @”/LM/W3SVC/1″</param>

        /// <param name=”VDirRoot”>e.g vKnowledge</param>

        /// <param name=”relPath”>e.g @”admin/Security/WinLogin.aspx”</param>

        /// <returns>e.g IIS://localhost/W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx</returns>

        public static string IISMetaPath(string SiteMetaPath, String VDirRoot, String relPath)


            SiteMetaPath = SiteMetaPath.Replace(@”/LM/”, “localhost/”);

            return @”IIS://” + SiteMetaPath + @”/root/” + VDirRoot + @”/” + relPath;



        /// <summary>

        /// SetIntegratedSecurityOnly

        /// </summary>

        /// <param name=”MetabasePath”>e.g IIS://localhost/W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx</param>

        public static void SetIntegratedSecurityOnly(string MetabasePath)


            if (MetabasePath != string.Empty)


                DirectoryEntry entry = null;

                if (!DirectoryEntry.Exists(MetabasePath))

                {   //Usually files are not  explicitly added to the IIS metabase


                    string sFolderPath = StringHelper.LeftBeforeLast(MetabasePath, @”/”);//metabasePath.Substring(0,metabasePath.LastIndexOf(“/”));

                    string sEntryName = StringHelper.RightAfterLast(MetabasePath, @”/”);// metabasePath.Substring(metabasePath.LastIndexOf(“/”) + 1);

                    DirectoryEntry folder = new DirectoryEntry(sFolderPath);

                    DebugHelper.PrintDirectoryEntryProperties(folder, sFolderPath);

                    //SchemaClassNames are listed in

                    string SchemaClassName = “IIsObject”;

                    //can’t assign “IIsWebFile” directly, causes HRESULT: 0x8000500F exception. E_ADS_SCHEMA_VIOLATION – The attempted action violates the directory service schema rules”.

                // see 

                    entry = folder.Children.Add(sEntryName, SchemaClassName);

//Fortunately ADSUTIL shows the WARNING: The Object Type of this object was not specified or was specified as IIsObject.

//This means that you will not be able to set or get properties on the object until the KeyType property is set.

                    entry.Properties[MetabasePropertyNames.keyType].Value = “IIsWebFile”;




                //must be created as new, even if entry was just created using Children.Add

                entry = new DirectoryEntry(MetabasePath);

                DebugHelper.PrintDirectoryEntryProperties(entry, MetabasePath);

                AuthFlags nAuthFlags =  (AuthFlags)(entry.Properties[MetabasePropertyNames.AuthFlags][0]);

                nAuthFlags = nAuthFlags & ~AuthFlags.AuthAnonymous; //clear anonymous

                nAuthFlags = nAuthFlags | AuthFlags.AuthNTLM; //Add Integrated

                entry.Properties[MetabasePropertyNames.AuthFlags][0] = nAuthFlags;

                // Chameleon sets Properties[“AuthNTLM”] and [“AuthAnonymous”] -does it work?

                 //virtualDirectory.Properties[“AuthNTLM”][0] = parametros.AuthNTLM;

                 //virtualDirectory.Properties[“AuthAnonymous”][0] = parametros.AuthAnonymous;






    public class MetabasePropertyNames

    {// from

        //TODO add all Properties

     public const string AuthFlags = “AuthFlags”;

     public const string keyType = “keyType”;




    public enum AuthFlags




        AuthNTLM = 4,

        AuthMD5 = 16,



    //Possible exceptions from

    // 0x80005006 – The property does not exist, or it does not exist at the access location where you are attempting to set it.

    //0x8000500C-The data type of the property is different than the data type to which you are attempting to set it.

    //0x8000500F exception. E_ADS_SCHEMA_VIOLATION – The attempted action violates the directory service schema rules”.  




The class uses my DebugHelper class and My StringHelper class




Reset DotNetNuke windows authentication back to normal.

In my previous posts (here and here)  I described the problems that I had to implemented mixed Authentication for DotNetNuke.
Important step for administrator is “Before switching to Windows Authentication ensure that your LAN acoount has host/administrative permissions for the portal.”.

If it wasn’t done, you can’t access administrative features. It is possible to use SQL command to re- activated Windows Authentication.

I am using call to SP  ModuleSettings_SiteSettings_Save that I’ve created previously.

exec dnn_ModuleSettings_SiteSettings_Save ‘WindowsAuthentication’,’false’

Note that DNN admin SQL page is not available and administrator should use some other SQL client to access your DNN database.

 SP ModuleSettings_SiteSettings_Save is the following:

CREATE PROCEDURE {databaseOwner}.[{objectQualifier}ModuleSettings_SiteSettings_Save]

      — Add the parameters for the stored procedure here

      @SettingName nvarchar(50),

      @SettingValue nvarchar(2000)




declare @SiteSettingsModuleId int

select @SiteSettingsModuleId={objectQualifier}Modules.ModuleID

FROM    dnn_Modules  INNER JOIN

                      {databaseOwner}dnn_ModuleDefinitions ON {objectQualifier}Modules.ModuleDefID = {objectQualifier}ModuleDefinitions.ModuleDefID INNER JOIN

                      {databaseOwner}dnn_DesktopModules ON {objectQualifier}ModuleDefinitions.DesktopModuleID = {objectQualifier}DesktopModules.DesktopModuleID

WHERE     ({objectQualifier}DesktopModules.FriendlyName = N’Site Settings’)


if NOT exists (select * from dbo.{objectQualifier}ModuleSettings WHERE  ({objectQualifier}ModuleSettings.SettingName = @SettingName) AND {objectQualifier}ModuleSettings.ModuleID =@SiteSettingsModuleId )

      INSERT INTO   {objectQualifier}ModuleSettings (ModuleID,SettingName,SettingValue)



      update    {objectQualifier}ModuleSettings

      set SettingValue=@SettingValue

      FROM         {objectQualifier}ModuleSettings

      WHERE     ({objectQualifier}ModuleSettings.SettingName = @SettingName) AND  {objectQualifier}ModuleSettings.ModuleID =@SiteSettingsModuleId





problems attempting to install a 2002 access deployment package on a machine with Windows 2003

Someone asked me with relation to my post Access 2003 Package Wizard – a big step BACK.
“I was wondering if you have run into problems attempting to install a 2002 access deployment package on a machine with 2003.  Does not seem to work.“

I’ve emailed him the following answer:

You should check MSDN article : “You may receive error messages when you install an Access 2002 runtime deployment package on a computer that is running Windows XP SP2 or Windows Server 2003”

 I am using batch file Win2003Setup.bat:

@rem Required to run to avoid error during “Access 2002” Setup
@rem “Office System Pack could not be installed on this computer as it requires Windows NT Service pack 6 or later.”
copy ….TroubleShootingsdbmsadsn.dll %windir%system32
@rem Required to exclude registration of MSCAL.OCX  to avoid error during “Access 2002” Setup
cscript MSCAL_NoRegister.vbs

where dbmsadsn.dll  is located in  ….TroubleShootings subfolder on my installation

and MSCAL_NoRegister.vbs file is the following:

Option Explicit
    Const ForReading = 1, ForWriting = 2, ForAppending = 3
    Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

Sub ReplaceLineTest()

Dim FSO ‘As FileSystemObject
Dim fSrc, fTrgt ‘As TextStream
Dim sFileName, sBackupName, sToFind, sReplace, strg
sFileName = “Setup.lst”
sBackupName = sFileName & “.Bac”
sToFind = “@MSCAL.OCX,$(AppPath),$(DLLSelfRegister)”
sReplace = “@MSCAL.OCX,$(AppPath),”
Set FSO = CreateObject(“Scripting.FileSystemObject”)
On Error Resume Next
 FSO.CopyFile sFileName, sBackupName, False
On Error GoTo 0
Set fSrc = FSO.OpenTextFile(sBackupName, ForReading)
Set fTrgt = FSO.OpenTextFile(sFileName, ForWriting)
Do While fSrc.AtEndOfStream <> True
    strg = fSrc.ReadLine
    strg = Replace(strg, sToFind, sReplace)
    fTrgt.WriteLine (strg)
Set FSO = Nothing
End Sub


Create CSS Links in DotNetNuke.

I wanted to have another page (not default.aspx) in DotNetNuke based application. I found that there is no common code to generate CSS links. Actually, core code to create CSS links is duplicated in a few places. I’ve created a common class, that can be used in my custom page, as well as  from Default.aspx and ComponentsSkinsSkin.vb . The class is posted in comment to the isssue. 

Using Configuration.Section to access subsection

I have a section in Web.Config:





I’ve tried to access inner section using shortcut “Section/Subsection“

string sSectionName=”applicationSettings/FSBusinessLib.My.MySettings”;
System.Configuration.ClientSettingsSection sectSettings = (ClientSettingsSection)config.Sections[sSectionName];

but it returned null.

The correct way is the following:

const string cnstApplicationSection = applicationSettings;
ConfigurationSectionGroup grpApplicationSection = config.SectionGroups[cnstApplicationSection];
string sSectionName=”FSBusinessLib.My.MySettings”;
System.Configuration.ClientSettingsSection sectSettings = grpApplicationSection .Sections[sSectionName];

This approach is used in my ConfigurationHelper class

Update Dynamic Web reference URLs During Installation in Visual Studio 2005

I am using dynamic URLBehavior for some web services and during Setup changing web services URLs to appropriate value according to approach described in  article “Walkthrough: Redirecting an Application to Target a Different XML Web Service During Installation “. 
As I already posted, Visual Studio 2005 changed the way where URLs are stored and now saves it inside section of config file. The differences between different types of projects are detailed described in post “How to share dynamic URLs across multiple Web Application Projects” .

I’ve created a class ConfigurationHelper, that helps to update the Dynamic URLs for Web Services.
I’ve tried to utilize ApplicationSettingsBase Class with SettingsProvider derived class to be called from Installer, but didn’t succesded.
It wasn’t too hard to implement it using  System.Configuration.Configuration/ClientSettingsSection and related classes.
One not obvious trick: when you assign value to the existing section element , it is required manually sectSettings.SectionInformation.ForceSave = true.

 Example of use the class:


String VDir = Context.Parameters[“VDir”]; //’TARGETVDIR
String Port = Context.Parameters[“Port”]; //’TARGETPORT
String Site = Context.Parameters[“TARGETSITE”]; //!5E74A5E75ECFD62E!183.entry
System.Configuration.Configuration config = ConfigurationHelper.OpenWebConfiguration(Site, VDir);
ConfigurationHelper.WriteDynamicUrl(config, “FSBusinessLib.My.MySettings”, “FSBusinessLib_CommonWS_CommonServices”, ServerName, VirtualDirectory, “CommonServices.asmx”);

//The class code is below:

namespace FSCSharpLib


    using Microsoft.VisualBasic;

    using Microsoft.VisualBasic.CompilerServices;

    using System;

    using System.Collections;

    using System.Diagnostics;

    using System.IO;

    using System.Reflection;

    using System.Windows.Forms;

    using System.Xml;

    using System.Web.Configuration;

    using System.Configuration;

    using FSHelperLib;

    //TODO Use Configuration/ConfigurationManager where appropriate

    //TODO merge with  AppSettingsHelper.cs

    public static class ConfigurationHelper


        public static System.Configuration.Configuration OpenWebConfiguration(string VDir,string Site )



        //’For example, if the IIS metabase path is W3SVC/1/Root/TraceDemo, then the path is “1/TraceDemo”??


            string SiteNumber = Site.Remove(0, Site.LastIndexOf(“/”) + 1);//retrieve “1” from @”/LM/W3SVC/1″;

            string RootVDir = “/” + VDir;//'”/vKnowledge”   

            Trace.WriteLine(“RootVDir “ + RootVDir + ” SiteNumber “ + SiteNumber);

            System.Configuration.Configuration configuration1 = WebConfigurationManager.OpenWebConfiguration(RootVDir, SiteNumber);

            return configuration1;



        /// from  not applicable for VS03 and in VS05 Web Site projects

        ///“applicationSettings” in VS05 WinForm projects and ClassLibrary projects



e.g “applicationSettings/FSBusinessLib.My.MySettings” or just “FSBusinessLib.My.MySettings”

        ///for CS FSBsnsCsLib.Properties.Settings

        ///for vb FSBusinessLib.My.MySettings



        public static System.Configuration.ClientSettingsSection FindOrCreateSettingsSection(Configuration config, string SectionName)


            const string cnstApplicationSection = “applicationSettings”;

            string sSectionName = StringHelper.RightAfterLast(SectionName, “/”);//remove “applicationSettings/” prefix if applicable ,



            //    sSectionName = cnstApplicationSection + ‘/’ + SectionName;


            ConfigurationSectionGroup grpApplicationSection = config.SectionGroups[cnstApplicationSection];

            if (grpApplicationSection == null)


                grpApplicationSection = new ApplicationSettingsGroup();

                config.SectionGroups.Add(cnstApplicationSection, grpApplicationSection);


            System.Configuration.ClientSettingsSection sectSettings = (ClientSettingsSection)grpApplicationSection.Sections[sSectionName];

            if (sectSettings == null)


                sectSettings = new ClientSettingsSection();

                grpApplicationSection.Sections.Add(sSectionName, sectSettings);

                sectSettings.SectionInformation.ForceSave = true;


                Debug.WriteLine(“Section name: {0} created”,     sectSettings.SectionInformation.Name);




        public static System.Configuration.ClientSettingsSection WriteSettingsValue(ClientSettingsSection sectSettings, string Key,string value)


            SettingElement elem = sectSettings.Settings.Get(Key);

            if (elem == null)


                elem = new SettingElement(Key,SettingsSerializeAs.String );

                XmlDocument doc= new XmlDocument();

                XmlElement xmlValue = doc.CreateElement(“value”);

                xmlValue.InnerText = value;

                SettingValueElement valueElem= new SettingValueElement();

                valueElem.ValueXml = xmlValue;

                elem.Value = valueElem;





                elem.Value.ValueXml.InnerText = value;

                sectSettings.SectionInformation.ForceSave = true; //important, changing Value.ValueXml value is not enough




        //don’t forget to call config.Save after finish all writes

        public static void WriteDynamicUrl(Configuration config,

          string SettingsGroupName, string SettingName, string ServerName,string VirtualPath,string ServiceFile)


            System.Configuration.ClientSettingsSection sectSettings  = ConfigurationHelper.FindOrCreateSettingsSection(config, SettingsGroupName);

            String sValue = HttpRequestHelper.HttpURL(ServerName, VirtualPath, ServiceFile);

            ConfigurationHelper.WriteSettingsValue(sectSettings, SettingName, sValue);



    }//end of class

}//end of namespace