About Us

Why DotNetNukeBlogs.com? Our goal is to be the premier aggregator of DotNetNuke related materials. DotNetNukeBlogs.com was started by DotNetNuke Core Team member employee community member Chris Hammond with the intention to provide a place for the leaders in the DotNetNuke Community to push their content to those needing it most, the users.

If you're a DotNetNuke Expert be sure to get your feed added into our aggregate system. You can read more about us here

DotNetNuke Hosting

Hosting for this website is provided by AppliedI.Net. Be sure to visit them for all your DotNetNuke Hosting needs. 

Latest Community DotNetNuke Blog Posts

DNN Connect
Tuesday, July 15, 2014 8:16:00 AM
I'm happy to announce we have found a location for next year's DNN Connect conference! The world's most convivial DNN event is returning to France. But instead of the bustling capital, we'll gather in the countryside in the town of Millau (world famous for the highest viaduct in the world). And just like last year we'll be introduced to the local flavours and ambience during our event, so get set for some of the local food and wine. These will be hand picked by our local team, the kind folks of Nevoweb. You know, the NBStore guys (and girls). They have booked the Domaine Saint Estève for us from the 28th to the 31st of May (the event itself being on the 29th and 30th). It's a luxurious resort in the heart of one of France's most beautiful natural regions (Parc des Grand-Causses/Cevennes national park).
DNN Connect
Monday, July 14, 2014 6:00:00 AM
As you probably already know, I love no-server-code Apps. They allow admins/web designers to extend their DNN without requiring host-permissions and without risking the system stability. It also allows them to modify the extension with very basic capabilities. When creating the ImageCompare App I ran into some common issues that you will have as well - and would like to share the lessons-learned here.
DNN Connect
Thursday, July 10, 2014 10:10:39 AM
This Blog is about 2 things. On one hand it's about Syntax-Highlighting, but actually it's more about creating safe No-Server-Code-Apps.
DNN Connect
Monday, June 30, 2014 4:36:25 PM
This is something of a pet peeve for me. And whenever I get myself involved in an open source project in DNN, it is one of the first things I’d tackle. The issue I’m referring to, here, is how to properly code settings that are serialized to storage (SQL). So settings are commonly retrieved as a hashtable or dictionary of key/value pairs that are both of a string type. These lists get stored in SQL typically in tables with the “Settings” suffix. I.e. ModuleSettings, PortalSettings, TabModuleSettings, etc. And often modules implement their own settings table because the framework hard wires ModuleSettings to … modules. So if you need portal-scoped settings for your module, you’ll need to create your own table. The old blog module (pre version 6) used to do this, for instance.
Peter Donker
Monday, June 30, 2014 4:33:47 PM

This is something of a pet peeve for me. And whenever I get myself involved in an open source project in DNN, it is one of the first things I’d tackle. The issue I’m referring to, here, is how to properly code settings that are serialized to storage (SQL). So settings are commonly retrieved as a hashtable or dictionary of key/value pairs that are both of a string type. These lists get stored in SQL typically in tables with the “Settings” suffix. I.e. ModuleSettings, PortalSettings, TabModuleSettings, etc. And often modules implement their own settings table because the framework hard wires ModuleSettings to … modules. So if you need portal-scoped settings for your module, you’ll need to create your own table. The old blog module (pre version 6) used to do this, for instance.

So, to begin with the worst of scenarios, let’s look at the version 3 code of the blog module. Here is a snippet from BlogList.ascx.vb:

    BlogSettings = Utility.GetBlogModuleSettings(Me.PortalId, TabId)
    If CType(BlogSettings("PageBlogs"), String) <> "" Then
     m_PersonalBlogID = CType(BlogSettings("PageBlogs"), Integer)
    Else
     m_PersonalBlogID = -1
    End If

The BlogSettings here is a hashtable that has been read from the database. It’s easy to see what is happening, here. First we retrieve the settings hashtable. Then we check if the value for the key “PageBlogs” is an empty string. Note that here is already a first mistake as this will throw an error if the key is not present. Then, if there is a string value there, it is parsed as an integer. Again, this would bomb if the string was not an integer, but this I’ll waive as only the module is setting this value. But it’s not pretty. Finally, if no value was found in the string the value is initialized to –1.

Now you’d look at this and go “yikes”, right? I hope so. Not only do we have several points of failure, we are also managing the settings very close to the UI layer. I.e. we are working to convert from and to settings values right in the codebehind of the ascx, whereas this should ideally be concentrated in the business layer. Not convinced? What if I told you this code reappears in Archive.ascx.vb, Blog.ascx.vb, ModuleOptions.ascx.vb, Search.ascx.vb and ViewBlog.ascx.vb. Messy enough for you? Indeed it’s unbelievable.

Strong typing means we create a wrapper around all this junk and all other code can refer to Settings.PageBlogs which happens to be an integer. So the first step is to create a separate class to hold your settings. For this example I’ll assume we’re doing a “simple” module which stores its settings in ModuleSettings. As you may know these module settings are actually propagated to the UI layer through the Settings property on the PortalModuleBase class that most of your controls inherit from. Again, this is a hashtable. And our goal will be to wrap this up as neatly as we possibly can so we don’t leak any settings management to other parts of our code.

Step 1: Create your settings class

Namespace Common
 Public Class ModuleSettings

#Region " Properties "
  Private Property ModuleId As Integer = -1
  Private Property Settings As Hashtable
  Public Property ShowProjects As Boolean = True
#End Region

What I’ve done is to add 3 properties to this class. The first two are internal properties that I’ll use to manage the settings. The latter (ShowProjects) is my first public setting that I need in my code. Note I’m already initializing the value of that setting. This is important as we’ll see later on.

Step 2: Create the constructor to deserialize the hashtable

  Public Sub New(ByVal ModuleId As Integer)
   _ModuleId = ModuleId
   _Settings = (New DotNetNuke.Entities.Modules.ModuleController).GetModuleSettings(ModuleId)
   ShowProjects = _Settings.GetValue(Of Boolean)("ShowProjects", ShowProjects)
  End Sub

Here we store the module id (which we need later if we want to save settings again) and we retrieve the hashtable, first. Then we try to get the value out of the hashtable to our setting. Note DNN now includes an extension method to simplify this process called GetValue. It does all of what the code did we saw earlier in the example from the blog module, but more efficiently. We now have one line and it will not throw an error if the value is not there and just use the default value if that is so (this is why we need to initialize our properties when we declare them). In fact, I’ve been nagging the core architects to have these methods available for us all so I didn’t need to code similar logic myself all the time.

Step 3: Add caching

For this we’ll use a static constructor as follows:

  Public Shared Function GetModuleSettings(ByVal ModuleId As Integer) As ModuleSettings
   Dim modSettings As ModuleSettings = Nothing
   Try
    modSettings = CType(DotNetNuke.Common.Utilities.DataCache.GetCache(CacheKey(ModuleId)), ModuleSettings)
   Catch
   End Try
   If modSettings Is Nothing Then
    modSettings = New ModuleSettings(ModuleId)
    DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey(ModuleId), modSettings)
   End If
   Return modSettings
  End Function

  Private Shared Function CacheKey(ByVal ModuleId As Integer) As String
   Return "ModuleSettings" & ModuleId.ToString
  End Function

Here we see how we can make sure we try to cache the complete settings object in DNN’s cache. Note, we let DNN take care of the caching time/expiration/etc.

Step 4: Saving the settings

  Public Sub Save()
   Dim objModules As New DotNetNuke.Entities.Modules.ModuleController
   objModules.UpdateModuleSetting(_ModuleId, "ShowProjects", Me.ShowProjects.ToString)
   DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey(_ModuleId), Me)
  End Sub

Saving becomes trivially easy as we have all the necessary bits and pieces in place. Note we are no longer doing the settings management for this in the codebehind of the edit control that is shown to the user when editing the settings. All is done within the settings class.

Step 5: Add to your base class

Of course you are using your own class that inherits from PortalModuleBase, right? No? Then you should. And here’s why:

  Private _settings As ModuleSettings
  Public Shadows Property Settings As ModuleSettings
   Get
    If _settings Is Nothing Then
     _settings = ModuleSettings.GetModuleSettings(ModuleId)
    End If
    Return _settings
   End Get
   Set(value As ModuleSettings)
    _settings = value
   End Set
  End Property

What happens here is that the Settings in the good old PortalModuleBase are now being replaced by our own settings class. So now, in your UI code you’ll just use Settings.ShowProjects to access our setting.

Shouldn’t we also do this in the core?

You can probably guess my answer. Yes, we should. You didn’t know that the core is still rife with the code I’ve been lamenting above? Check out the latest source version (7.3.1 as of this writing) and head over to UserController.cs lines 256 and below. You’ll notice blocks like these:

            if (settings["Profile_DisplayVisibility"] == null)
            {
                settings["Profile_DisplayVisibility"] = true;
            }

Here the settings dictionary is being primed to catch errors in case no value is there. Oh dear. That means that the conversions are done at the end point in code. And if we search for the specific string we’ll find it in lines 59-66 of Profile.ascx.cs:

        protected bool ShowVisibility
        {
            get
            {
                object setting = GetSetting(PortalId, "Profile_DisplayVisibility");
                return Convert.ToBoolean(setting) && IsUser;
            }
        }

As we can see we have the string Profile_DisplayVisibility appearing three times. And if they need this setting more often, this string would keep on appearing. The repetition of this string has two major drawbacks: (1) it increases the likelihood of a coding errors by those working on the core code (if you’d misspell Profile_DisplayVisibility you won’t get the setting) and (2) it makes it more difficult for people like myself that work just with the API of the core to determine which settings there are, what type they are and what they’re called. This begs for refactoring. And I sincerely hope this post will make it clear what it is I’m after. I’ve gone ahead and coded a start for this bit of the framework. So if you examine the UserSettings they consist of a set of “sections” (Profile, Security, etc). This can easily be done in a very elegant way as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Controllers;
using DotNetNuke.Entities.Portals;

namespace DotNetNuke.Entities.Users
{
    class UserSettings
    {
        public const string CacheKey = "UserSettingsPortal{0}";

        #region Public Properties
        private int PortalId { get; set; }
        private string CultureCode { get; set; }
        public ProfileSettings Profile { get; set; }

        #endregion

        public static UserSettings GetUserSettings(int portalId, string cultureCode)
        {
            string cacheKey = string.Format(CacheKey, portalId);
            return CBO.GetCachedObject(new CacheItemArgs(cacheKey, DataCache.PortalSettingsCacheTimeOut, DataCache.PortalSettingsCachePriority, portalId, cultureCode), GetUserSettingsCallback, true);
        }
        private static object GetUserSettingsCallback(CacheItemArgs cacheItemArgs)
        {
            var portalId = (int)cacheItemArgs.ParamList[0];
            var cultureCode = (string)cacheItemArgs.ParamList[1];
            Dictionary settingsDictionary = (portalId == Null.NullInteger)
                                                ? HostController.Instance.GetSettingsDictionary()
                                                : PortalController.GetPortalSettingsDictionary(PortalController.GetEffectivePortalId(portalId));
            UserSettings res = new UserSettings();
            res.Profile = new ProfileSettings(settingsDictionary);
            return res;
        }

        public void Save()
        {
            PortalController.UpdatePortalSetting(PortalId, "Profile_DefaultVisibility", Profile.DefaultVisibility.ToString(), false, CultureCode);
            PortalController.UpdatePortalSetting(PortalId, "Profile_DisplayVisibility", Profile.DisplayVisibility.ToString(), true, CultureCode);
        }


        class ProfileSettings
        {
            #region Public Properties
            public int DefaultVisibility { get; set; }
            public bool DisplayVisibility { get; set; }
            #endregion

            public ProfileSettings(Dictionary settingsDictionary)
            {
                DefaultVisibility = settingsDictionary.GetValue("Profile_DefaultVisibility", DefaultVisibility);
                DisplayVisibility = settingsDictionary.GetValue("Profile_DisplayVisibility", DisplayVisibility);
            }
        }

    }
}
This implements the four first steps listed above and as a bonus stacks the settings so you could use UserSettings.GetUserSettings(portalId, cultureCode).Profile.DefaultVisiblity. Now that would be a lot clearer. And here’s another good reason to take the time to do this: we can document these properties. Making the framework even more insanely easy to work with.
More ...
Tags: Development
Ultimate DNN Modules
Friday, June 27, 2014 9:54:53 AM
As we promised ever, we always maintain the independent branch of SunBlogNuke compatible well with older version of DNN  CMS, such as the DNN4-building. Today we would like to announce that we have built another compatible package of SunBlogNuke for DNN5.2+. Even through you are still using the DotNetNuke 5, you don’t have to be worry about it and just feel free to let it there without any update as you like. Surely, the development status is still active; we will include updates with fixes if necessary. You can get it here. We hope that with this generation dnn blog module  you can enjoy the blog writing and it will make your life better; plus if you have any good advice about our products, please feel free to leave a comment or contact us. Note: 1) If your dnn website is DNN5.2 above, you should ignore this package and get more latest package. 2) We may need a quote for premium support for those compatible buildings and our cost will be $25/hour. ----------------------------------------- ...
Engage
Thursday, June 26, 2014 12:07:00 PM

At Engage we believe in investing in the professional development of our employees. While building professionals who can effectively communicate with our customers has always been a priority for us, we also stress a healthy work-life balance.

Recently, I revisited one of the most influential books I've read - The 7 Habits of Highly Effective People. I've read (or listened to) the book four times now throughout my life. Not only does it teach us how to be more "effective" but also reinforces work-life balance principles. I highly recommend it to everyone - especially those who are members of a team.

Realizing how powerful the material is, we've decided to weave The Habits into the Engage culture. This started with an overview/kick-off session where we all took the 7 Habits personal assessment. Based on how we scored, we will all teach one of the 7 Habits to the group - one Habit at a time. While I look forward to a continued deeper understanding of the material (internalizing the habits), most of all I look forward to seeing how our outstanding young professionals can become even more effective in their lives. Our journey awaits, Habit 1: Be Proactive coming next week to Engage...


More ...
DNN Connect
Wednesday, June 25, 2014 9:27:00 AM
This is part of a blog post series accounting for user management in DNN using the User account modules from DNN-Connect, all available as open source extensions on Github.com. Currently we have three different modules available, one for letting people register on the site, one for letting folks update their account details and one for managing user accounts from ad administrative perspective.
ChrisHammond.com
Monday, June 16, 2014 11:19:23 AM
If you’ve recently upgraded to DotNetNuke 7.3, you might not have noticed that your scheduled tasks aren’t running. How do you know if your tasks are running or not? Follow these steps
Engage
Monday, June 16, 2014 3:00:00 AM

What is the latest version of DotNetNuke? Well for starters, these days the DotNetNuke moniker has been dropped by DNN Software. Now it's just DNN. The most current version is DNN 7.3 and it was released on June 11, 2014

ChrisHammond.com
Saturday, June 14, 2014 1:40:55 AM

With the release of DNN 7.3.0 this week, it was time for me to get my sites upgraded. I upgraded most of the sites without any issues, but wanted to point out a few errors that I received on sites, and how I resolved them.

The very first upgrade I did started out bad, it was for this site, and while the upgrade was 100% successful, as soon as I tried to load the site I got a generic 500 error. Accessing the site from the webserver gave me a little more information, seen below, but not much.

DNN Connect
Thursday, June 12, 2014 8:42:00 AM
For the DNN-Connect event in Italy, we demonstrated how to create a powerful feature-rich DNN-App in 1 hour. Here you'll find the live-demo, the live-recording from DNN-connect and you'll be able to download the App for any modifications. + you will discover how to create similar Apps with similar effort. Go for the low hanging fruits :)          
Engage
Tuesday, June 10, 2014 8:49:00 AM

2014 is shaping up to be a banner year for us. In an age where 90% of tech start-ups fold within their first five years of existence, we celebrated our 15th anniversary last month – May 26, to be exact. Over time, our company has grown from a consulting firm, to a leader in the DNN community, and now a full-service web development firm that serves a diverse set of organizations.

 

DNN Connect
Monday, May 26, 2014 1:00:00 PM
Wow.  After many, many months of prep and thinking and work, DNN Connect is now a memory.  Amazing how so much work can go into something and just like that it’s over.  BUT, what an awesome experience!
DNN Connect
Saturday, May 24, 2014 5:20:00 AM
Let's get strategic - and break some points. Not share-points but breakpoints :). To understand the challenge: we're creating a website and want it to be responsive. One of the aspect of a responsive site is that it responds to the screen size - presenting the content as best as possible at every possible screen size - and there are thousands of screen sizes - multiplied by browser types and you'll get a lot of test scenarios - too many, to be exact. So we need a strategy.
DNN Connect
Monday, May 19, 2014 6:30:00 AM
We are happy to announce that starting from March 1st DNN-Connect has the official status of a non-profit association governed by the present statutes and Articles 60 et seq. of the Swiss Civil Code.
DNN Connect
Saturday, May 17, 2014 5:20:00 AM
I’m thrilled to announce the birth of an association dedicated to the DNN Platform: DNN-Connect. You may already have heard of our website. We’re now taking things to a new level with the creation of an association. Why an association, you ask? Allow me to explain...
DNN Connect
Thursday, May 15, 2014 10:57:00 AM
Razor is the future for most output-oriented .net stuff. This also applies to WebForms-based CMS like DNN. But fortunately, they got it right and added Razor-Support about 2 years ago. So here goes: all the ways you could use to access SQL-data directly from Razor without pre-compiling something. So no Entity-Framework or similar. The five options we'll review are: PetaPoco, SQLReader, DataTable, 2sxc-DataPipelines
DNN Connect
Wednesday, May 14, 2014 11:10:00 AM
Inspired by Nik Kalyani's keynote address in Chicago... I thought to myself... 'hmm, maybe I can serve the DNN Community by putting on a Day of DNN in Nova Scotia?' and so I did. Ack!
Engage
Monday, May 12, 2014 11:31:00 AM

Nothing is more frustrating than trying to read a company’s Web site on your phone and having to scroll up and down, zoom in and out, and strain your eyes until you find the right information–especially when you’re in a hurry.

RSS URL

Resources

DotNetNuke.com The DNN mothership.

Built by

This site is built and managed by Christoc.com Software Solutions, a leading .NET open source consulting company.