All DNN requests run within what’s known in an HttpContext, i.e. a context of an http web request. I say all, but this is not entirely true. Nearly all DNN requests run through HttpContext. There are a number of circumstances under which your code will not run within an HttpContext. This can be because the code runs as a result of a scheduled service or because you’ve decided to spark off a new thread. If you do have code that runs outside HttpContext, there is an evil ‘bug monster’ lurking in the core. This is the PortalSettings object. More specifically, the GetCurrentPortalSettings static method on this PortalController that returns this object. Allow me to explain.
What is the PortalSettings object? It is a collection of parameters that define in which DNN portal context the user is. So this includes most of the parameters set by the Administrator under the Site Settings, but also some context parameters such as the HttpAlias (remember that a single portal can respond to/have multiple aliases). The portal settings are made in the Url rewriter module. The latter is a piece of code that runs on every regular Http page request to DNN. It analyzes the url and distills the correct portal from this. The portal parameters are loaded and the extra contextual variables are added to this. The whole object is then stored in the variables that all subsequent code that runs in that thread can draw from. The GetCurrentPortalSettings method draws this object from the place it is stored.
So what is the PortalSettings used for? Well, in short it is used all over the place. It is the default method to find out what the current portal is, amongst others. If you search in the DNN source code for usages of GetCurrentPortalSettings you’ll get a very, very long list of calls.
So what’s the issue? The issue is that outside the HttpContext the PortalSettings object is not available. “A”, I hear you say, “that makes sense as we have no HttpAlias”. Well, yes and no. Sometimes we need to access portal settings from our code that is running outside the HttpContext. It is quite thinkable that I have a PortalID and I’d like to have my Portal’s Settings. Hmm, but we have the PortalInfo object, no? The PortalInfo is a lot like the PortalSettings. It is the container for the settings under Site Settings, so it only misses the contextual info like the HttpAlias. Correct. We could use this object to access our settings. But unfortunately a lot of DNN methods rely on the PortalSettings object. So many (and I mean a lot) of calls to the framework will start to throw exceptions. The aforementioned usages list underlines what the extent is of this ‘problem’.
To add to the predicament, later (I believe post 04.06.xx) versions of the Url Rewriter no longer set the PortalSettings object if the call is not to a DNN or other aspx page. I was once faced with a lot of rewriting as I was using an .axd extension to handle some calls to my code.
An illustration
I have a scheduled task that checks in the database for notifications to be sent. For these notifications I use token replace and a url to the site. The url needs an HttpAlias so this immediately brings home the problem. But DNN’s token replace (used to personalize text blocks) heavily relies on the PortalSettings object. This object is unavailable as it is a scheduled task.
Solutions?
The solution to this problem is not easy. My first thought was:
1. Introduce a site setting where the preferred HttpAlias is set. Admins set this and are aware that for instance emails sent outside HttpContext will link back to this address in my example.
2. GetCurrentPortalSettings gets a sister where you specify a PortalID. If the PortalSettings have already been constructed and the IDs match, then use those. If not, than reconstruct.
3. Start carrying the PortalID throughout the code that relies deep down on the PortalSettings object
Point 3 above is probably the most problematic of the changes. It will change the signature of many methods.
Another approach would be to ‘kick’ DNN to set the PortalSettings in the current thread. You could have a method SetCurrentPortalSettings which takes a portal ID and sets the object that all subsequent calls can use through GetCurrentPortalSettings.
Conclusion
In my opinion the reliance on PortalSettings within the DNN framework is such that we need a proper way to have them outside an HttpContext.