hgs yükleme
My Cart (0)  |  My Orders  |  My Downloads  |  My Auction  |  My Account  |  Help

Login |Register        Search

Advanced dotnetnuke module development - Settings Management

                Print      Add To Favorite     Add To Watch List     Contact Author

Creator: host   9/11/2012 3:55:17 AM    Author: Peter Donker   Source: http://www.dotnetnuke.com/Resources/Blogs/EntryId/3480/Advanced-Module-Development-The-Data-Layer.aspx   Views: 2995    0    0  
Module develop Data Access Dnn development module development Module Settings

Hi there again. Today’s topic for some deep exploration is how to manage your module’s settings in code. As I stated in my previous posts (here and here), most examples of DotNetNuke module development out in the wild are fine for a first shot at a module, but won’t hack it when you begin to get serious with module development. And if you don’t believe me: come to a DNN event and ask any one of the more experienced DNN Store vendors. It’s not that the Hello World examples suck. It’s just not sustainable when you’re building your module for world domination.

So once again: hi, my name is Peter Donker. I run a small business called Bring2mind which specializes in document management on the DotNetNuke platform.

Me with my DNN wizard hat on.

Module settings at the “Hello World” level

Even the most trivial of modules will have some settings that the admin/editor can change to control behaviour. Commonly we store these in a “property bag” called Settings which is a property of the base class of our module’s code (PortalModuleBase). This property bag comes in the form of a hashtable. So a list of object/object pairs. The values of these stored in a table called ModuleSettings … as strings. So the objects will get serialized to strings. What does that mean? Well, if you add a setting as follows:

Me.Settings.Add(“Foo”, bar)

Where bar is not a string, then .net will attempt to convert that to a string for you. This, already, is not a good idea. You don’t want .net to control your serialization unless you’re absolutely sure it does it correct both ways. Another thing to dislike about it is that it expects the first parameter to be a string or to convert to one. It is implicit. Not explicit. Nowadays we’d use a NameValueCollection to do this, but those weren’t around when Module Settings were first invented. So tough luck. You’re going to have to keep an eye on those conversions yourself.

Now when we add or draw out information from our settings we use that first parameter as identifier. Duh. That’s simple enough. So

FacebookAppId = CStr(Settings(“FacebookAppId”))

Is what you’d typically see. Note you get the ugly conversion bits floating around here as the hashtable returns objects (unless you are programming with option strict off, which I’d never do). Of course this doesn’t work when the property bag is empty or this value has not been added yet. You’ll get a big fat error as null doesn’t convert to a string. So typically we’d see this:

If Not Settings("xmlsrc") Is Nothing xmlsrc = CType(Settings("xmlsrc"), String) End If

This is pretty bulky to just retrieve a setting. And note you are writing the name of the setting twice in your code. Which is a pity as it violates the rule “keep the amount of times you write a key as a plain string in your code to a bare minimum”. Reread that and if necessary post it above your monitor. You would not be the first one to spend hours debugging an issue that was caused by a misspelt key somewhere. I have worked on code where the above pattern was repeated across several ascxs in the same project and even in several methods within those ascxs. This explodes the number of times you’re writing your key value.

Step 1: Taking the settings aside in their own class

The first thing to do is to do away with this diarrhea of hastable conversions across your code. Get all of this abstracted into your own settings class. Your class will have regular properties with their types instead of dealing with the flux of objects and implicit conversions. This is simple enough. You get something like this:

Public Class ModuleSettings 
Private _moduleId As Integer = -1

Private _DefaultCacheTime As Integer = 30

Public Property DefaultCacheTime() As Integer

Get Return _DefaultCacheTime End Get
Set(ByVal Value As Integer) _DefaultCacheTime = Value End Set
End Property

Public Sub New(ByVal ModuleId As Integer) _moduleId = ModuleId
Dim settings As HashTable = (New DotNetNuke.Entities.Modules.ModuleController).GetModuleSettings(ModuleId)
If settings("DefaultCacheTime") IsNot Nothing Then DefaultCacheTime = CInt(settings("DefaultCacheTime"))
End If
End Sub

Public Sub Save()
Dim objModules As New DotNetNuke.Entities.Modules.ModuleController
objModules.UpdateModuleSetting(_moduleId, "DefaultCacheTime", Me.DefaultCacheTime.ToString)
End Sub

End Class

This is already a lot better. Here we see that now we can use the property DefaultCacheTime in our code. As a bonus: it has been primed with a value in case there are no settings! We are now half way to enlightenment. We have now reduced the occurrence of “DefaultCacheTime” as a string to 3. But we can do better as we’ll see later. But first let’s talk inheritance.

Step 2: Completely hiding the hashtable

The next step is to override the PortalModuleBase and inject a class of your own that your ascxs inherit from. This allows you to intervene and remove the ugly duckling Settings and replace it with the beautiful swan version of Settings:

Public Class Modulebase Inherits Entities.Modules.PortalModuleBase 
Private _modSettings As ModuleSettings Public Shadows Property Settings() As ModuleSettings
If _modSettings Is Nothing Then _modSettings = ModuleSettings.GetModuleSettings(ModuleId)
End If
Return _modSettings End Get
Set(ByVal value As ModuleSettings) _modSettings = value
End Set
End Property
End Class

As you can see the Settings shadow the base settings. So now in your codebehind you’d write:


Your enlightenment is now almost complete. We will now revisit the ModuleSettings class you created.

Step 3: Perfecting the settings class

One thing I’m not that happy with is the “if settings(‘foo’) is not nothing then read its value”. I find it bulky and when you have a lot of settings it begins to really create tons and tons of code. So here’s a new radical idea: let’s draw out those values with extension methods. Check out this method:

 Public Sub ReadValue(ByRef ValueTable As Hashtable, ByVal ValueName As String, ByRef Variable As Integer) 
If Not ValueTable.Item(ValueName) Is Nothing Then
Try Variable = CType(ValueTable.Item(ValueName), Integer)
Catch ex As Exception
End Try
End If
End Sub

This does the conversion based on its availability and even puts the Try-Catch in case the value was not really an integer. The result is that Variable will only be loaded if that value has been found and is a valid integer. This is what the logic should do. You can even make this a function returning a boolean if the value was read or not. For now I’ll leave it as a method. So now our code in the settings constructor becomes:

settings.ReadValue(“DefaultCacheTime”, DefaultCacheTime)

And we overload with all other data types that we need (pay especial attention to date conversions!). There is another minor benefit to this approach: now I get to see the New and Save methods on one screen in code and I can easily spot any omissions or misspellings. The code becomes really compact and we have limited the string key values to 2! One for reading and one for writing. Note: you could of course create a variable for the key name and reduce that to 1. And I’m not against that. But 2, especially when you can see on the same page, is in my opinion an adequate reduction of failure risk already.

Final Words

I should also mention IPortable. Implementing this requires you to serialize and deserialize your settings. You can now offload that code to your settings class and make sure this stays in one place.

So there you have it. This is how I approach settings. It’s typically the first thing I tackle when I get involved in an existing module project (Blog/Newsfeeds). It is not hard to do and it really cleans up a lot of code (the blog module code is still marred by other issues, but that’d be the topic of another post). Hopefully the extension methods will make it into the DNN core one day. In my Document Exchange I have now created them for various types of variables and collections. So I can also use them on Request.Params for instance. Simple and effective.

Rating People: 14   Average Rating:     

     DnnModule.com is built to provide DNN quality modules and DNN skins, some of them are free, some not. We wish these stuffs (free or not ) can be useful to you.

     Besides that, we also provide a full range of professional services, ranging from web site build, seo, system management, administration, support, senior consultancy and security services. We act as if your development project or network was ours, with care and respect. We are not satisfied until it works the way you want it to, and we don't silently ignore found issues as somebody else's problem.