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.)


 

Advertisements

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)->


RoleController.SynchronizeRoles(PortalId)->


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);

            if(bRet==true)

            { //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;

                            break;

                        }

                    }

                }//foreach

            } //ManifestResourceExist

            if(bRet==false)

            {

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

                if (ThrowException == true)

                {

                   throw new ApplicationException(sMsg);

                }

                else

                {

                    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)

            {

                bRet=false;

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

                if (ThrowException)

                {

                    throw new ApplicationException(sMsg);

                }

                else

                {

                    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(http://www.123aspx.com/redir.aspx?res=33760 and

    /// Creating Virtuals and reading Installed Sites on IIS with .Net(http://west-wind.com/weblog/posts/399.aspx )    </remarks>

    public class IISMetaDataHelper

    {

        //For debugginh it is convinient to use adsutil.vbs http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/d3df4bc9-0954-459a-b5e6-7a8bc462960c.mspx

        /*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);

            SetIntegratedSecurityOnly(MetabasePath);

        }

        /// <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

                    //See http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic12899.aspx

                    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 http://blog.crowe.co.nz/archive/2006/06/01.aspx

                    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 http://groups.google.com.au/group/microsoft.public.adsi.general/browse_frm/thread/3b339d218e673aca/050974e5903530e3 

                    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”;

                    folder.CommitChanges();

                    entry.CommitChanges();

                }

                //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;

                entry.CommitChanges();

             }

        }

    }//class

 

    public class MetabasePropertyNames

    {// from http://technet2.microsoft.com/WindowsServer/en/Library/271ae19b-853f-4672-b743-5ba126e902db1033.mspx?mfr=true

        //TODO add all Properties

     public const string AuthFlags = “AuthFlags”;

     public const string keyType = “keyType”;

 }

   

    [FlagsAttribute()]

    public enum AuthFlags

    {//from http://technet2.microsoft.com/WindowsServer/en/Library/271ae19b-853f-4672-b743-5ba126e902db1033.mspx?mfr=true

        AuthAnonymous=1,

        AuthBasic=2,

        AuthNTLM = 4,

        AuthMD5 = 16,

        AuthPassport=64

    }

    //Possible exceptions from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/generic_adsi_error_codes.asp

    // 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)


AS


BEGIN


 


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)


      values(@SiteSettingsModuleId,@SettingName,@SettingValue)   


else


      update    {objectQualifier}ModuleSettings


      set SettingValue=@SettingValue


      FROM         {objectQualifier}ModuleSettings


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


END


 


go


 

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 :http://support.microsoft.com/?id=837150 “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
Setup.exe

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
ReplaceLineTest


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)
Loop
fSrc.Close
fTrgt.Close
Set FSO = Nothing
End Sub