Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Nov
20
Written by:
Thursday, November 20, 2008 4:01 PM
A couple of weeks ago I posted some advice on the DotNetNuke forum regarding the use of the 'NavigateURL' call. Through my work on Friendly Url Providers I've become a bit of a walking reference for this particular corner of the DNN framework. So I posted a short description on all the different overloads for the NavigateUrl call.
In it, I posted the cheerful snippet:
"[Same as the other NavigateUrl overloads] but allows you to pass in your own portalSettings instance. This allows you to define different portal options, so you can either change the current language, change the portal alias, or even generate urls for a different portal altogether. All overloads without 'portalSettings' produce Urls for the current portal, with all the current settings like the current language, current portal alias and more. You would also supply the 'portalSettings' value for use when the portalSettings is not in the current context, such as in DotNetNuke scheduled events - the current portal settings is only created and stored in the context.items when the request is as a result of a 'user' request to the website. Scheduled Items can be triggered by a timer and as such don't always have the 'portalSettings' instanced. An example would be generating links for an automated email created in a scheduled task."
The reason I posted this much information specifically about scheduled tasks, is that I've built a few now, and I know that using the DotNetNuke framework in 'scheduled task' mode can be a bit tricky. The reason is that when a scheduled task is kicked off, it's done in a different application thread to the main asp.net application, and as such, many of the Http items that the DNN framework takes for granted are missing. There's just one problem with this detailed advice, as we will find out, it's total hogwash and doesn't work.
What really happens when you provide your own PortalSettings
In the last day or so, I've been working on a DNN schedule item that does exactly what I posted in my forum response : generates an email to send to users, and in that email is links to pages within the site. Of course, as any good DNN developer knows, to get Page Urls, you use the DotNetNuke.Common.Globals.NavigateUrl() call. And, forgetting my own advice, the first thing I tripped up on was a 'object reference not set' error. A quick trace, a short slap to the forehead - of course! No Context.Items["PortalSettings"] instance, because there's no HttpContext.Current instance in a DNN schedule item thread. Incidentally, the check in the HttpContext for the PortalSettings call is this method, in 'PortalController.vb'
Public Shared Function GetCurrentPortalSettings() As PortalSettings
Return CType(HttpContext.Current.Items("PortalSettings"), PortalSettings)
End Function
Note that this method doesn't first check to see if HttpContext.Current is a valid reference - it's just assumed that it will be.
So, I dutifully took my own advice and came up with a new PortalSettings instance- easy peasy, I thought, I'll just grab the first portal alias in the list, and create a new portal settings object like this:
PortalSettings ps = new PortalSettings(-1, alias.HttpAlias);
Whoops! That doesn't work either. Why? Because, believe it or not, one of the things in the Portal Settings constructor actually seems to check the Current Portal Settings. This wouldn't be so bad (as it copes with 'null' as a return value), except that it assumes that the HttpContext.Current will never be null.
Back to Square One with the Portal Settings Constructor
So I sat down and wrote a whole procedure which replicated the constructor for the portal settings object, only in C# to match the project I was working on. This worked OK, after I removed the code that expected the HttpContext.Current to be a valid value. Armed with my new PortalSettings instance, I then called the NavigateUrl() call overload that allows you to pass in your own PortalSettings instance. I sat back, ran my code and waited for the output of a set of perfectly formed Urls.
I didn't have to wait long, as I got the long and wordy stream of Exception text back instead. Seems as though, even if you supply the PortalSettings object into the NavigateUrl overload, one of the first things it does is check the 'GetEnabledLocales' method, and the first line in that call is ... you guessed it 'PortalController.GetCurrentPortalSettings()' - which, as shown above, checks the HttpContext for the current portal settings. Now this is a bit of a silly situation - providing an overload to supply your own PortalSettings instance, and then checking the current Context for a PortalSettings instance. I'll probably log this one in Gemini to fix.
Interesting Sidebar to this Discussion
I often get people reporting 'object not set' reference errors when using various DNN modules and the Url Master / iFinity Friendly Url Provider modules. Normally, this shows up in a stack trace as eminating from the 'GetEnabledLocales' procedure, like this:
System.NullReferenceException: Object reference not set to an instance of an object. at DotNetNuke.Entities.Portals.PortalController.GetCurrentPortalSettings()
The reason for this is that it is the DotNetNuke UrlRewriter that is responsible for adding the current PortalSettings object into the HttpContext.Current.Items collection. The Url Master / Friendly Url Provider modules have a set of filters designed to stop requests at different points of processing. The 'ignoreRegex' filter means the UrlRewriter ignores the request completely, while the 'doNotRewriteRegex' ensures that the request is not rewritten, but still allows the PortalSettings to be created and added to the context. So if you've got this error, what you want to do is craft your 'ignoreRegex' to let the request through, but the 'doNotRewriteRegex' to block it. In between these two filters is the code to identify the portal and store the PortalSettings object in the HttpContext.
So, getting back to my project... what to do now? I still need to call 'NavigateUrl' without a HttpContext. I decided to go back to Square Zero and mock up the HttpContext completely, the same as I have done in my series of unit testing DotNetNuke modules.
Forward to Square Two with the PortalSettings Constructor
(I've always assumed it's square two that you move on to from square one, not circle one - some sort of integer over shape preference, I presume)
To fix the missing HttpContext problem without butchering up the DNN Core with custom fixes, I simply added a butchered up mock HttpContext constructor, in which I would stash my created portal settings. This creates a fake HttpContext object, stores the PortalSettings in the items collection, and the rest of the DNN Framework appears none the wiser. My Schedule Program now generates Emails with the correct Urls embedded, and I've got a bit of custom portal settings code to use next time I head up this pathway.
Here's the code. Don't use it unless you know what you're using it for, and if you're working on a high load server, probably best to make sure the threads are being disposed of correctly. Please don't ask me for a VB version either : go and find a C#/VB.NET Converter. The code is taken from the DNN Core, so all the usual legal messages in the DNN code files applies.
public static DotNetNuke.Entities.Portals.PortalSettings CreateNewPortalSettings(int portalId)
{
//new settings object
PortalSettings ps = new PortalSettings();
//controller instances
PortalController pc = new PortalController();
TabController tc = new TabController();
PortalAliasController pac = new PortalAliasController();
//get the first portal alias found to be used as the current portal alias
PortalAliasInfo portalAlias = null;
PortalAliasCollection aliases = pac.GetPortalAliasByPortalID(portalId);
string aliasKey = "";
if (aliases != null && aliases.Count > 0)
{
//get the first portal alias in the list and use that
foreach (string key in aliases.Keys)
{
aliasKey = key;
portalAlias = aliases[key];
break;
}
}
//get the portal and copy across the settings
PortalInfo portal = pc.GetPortal(portalId);
if (portal != null)
{
ps.PortalAlias = portalAlias;
ps.PortalId = portal.PortalID;
ps.PortalName = portal.PortalName;
ps.LogoFile = portal.LogoFile;
ps.FooterText = portal.FooterText;
ps.ExpiryDate = portal.ExpiryDate;
ps.UserRegistration = portal.UserRegistration;
ps.BannerAdvertising = portal.BannerAdvertising;
ps.Currency = portal.Currency;
ps.AdministratorId = portal.AdministratorId;
ps.Email = portal.Email;
ps.HostFee = portal.HostFee;
ps.HostSpace = portal.HostSpace;
ps.PageQuota = portal.PageQuota;
ps.UserQuota = portal.UserQuota;
ps.AdministratorRoleId = portal.AdministratorRoleId;
ps.AdministratorRoleName = portal.AdministratorRoleName;
ps.RegisteredRoleId = portal.RegisteredRoleId;
ps.RegisteredRoleName = portal.RegisteredRoleName;
ps.Description = portal.Description;
ps.KeyWords = portal.KeyWords;
ps.BackgroundFile = portal.BackgroundFile;
ps.GUID = portal.GUID;
ps.SiteLogHistory = portal.SiteLogHistory;
ps.AdminTabId = portal.AdminTabId;
ps.SuperTabId = portal.SuperTabId;
ps.SplashTabId = portal.SplashTabId;
ps.HomeTabId = portal.HomeTabId;
ps.LoginTabId = portal.LoginTabId;
ps.UserTabId = portal.UserTabId;
ps.DefaultLanguage = portal.DefaultLanguage;
ps.TimeZoneOffset = portal.TimeZoneOffset;
ps.HomeDirectory = portal.HomeDirectory;
ps.Version = portal.Version;
ps.AdminSkin = SkinController.GetSkin(SkinInfo.RootSkin, portalId, SkinType.Admin);
if (ps.AdminSkin == null)
{
ps.AdminSkin = SkinController.GetSkin(SkinInfo.RootSkin, DotNetNuke.Common.Utilities.Null.NullInteger, SkinType.Admin);
}
ps.PortalSkin = SkinController.GetSkin(SkinInfo.RootSkin, portalId, SkinType.Portal);
if (ps.PortalSkin == null)
{
ps.PortalSkin = SkinController.GetSkin(SkinInfo.RootSkin, DotNetNuke.Common.Utilities.Null.NullInteger, SkinType.Portal);
}
ps.AdminContainer = SkinController.GetSkin(SkinInfo.RootContainer, portalId, SkinType.Admin);
if (ps.AdminContainer == null)
{
ps.AdminContainer = SkinController.GetSkin(SkinInfo.RootContainer, DotNetNuke.Common.Utilities.Null.NullInteger, SkinType.Admin);
}
ps.PortalContainer = SkinController.GetSkin(SkinInfo.RootContainer, portalId, SkinType.Portal);
if (ps.PortalContainer == null)
{
ps.PortalContainer = SkinController.GetSkin(SkinInfo.RootContainer, DotNetNuke.Common.Utilities.Null.NullInteger, SkinType.Portal);
}
ps.Pages = portal.Pages;
ps.Users = portal.Users;
// set custom properties
if (DotNetNuke.Common.Utilities.Null.IsNull(ps.HostSpace))
{
ps.HostSpace = 0;
}
if (DotNetNuke.Common.Utilities.Null.IsNull(ps.DefaultLanguage)) {
ps.DefaultLanguage = DotNetNuke.Services.Localization.Localization.SystemLocale;
}
if (DotNetNuke.Common.Utilities.Null.IsNull(ps.TimeZoneOffset)) {
ps.TimeZoneOffset = DotNetNuke.Services.Localization.Localization.SystemTimeZoneOffset;
}
ps.HomeDirectory = DotNetNuke.Common.Globals.ApplicationPath + "/" + portal.HomeDirectory + "/";
// get application version
string[] arrVersion = DotNetNuke.Common.Assembly.glbAppVersion.Split('.');
int intMajor = 0;
int intMinor = 0;
int intBuild = 0;
Int32.TryParse(arrVersion[0], out intMajor);
Int32.TryParse(arrVersion[1], out intMinor);
Int32.TryParse(arrVersion[2], out intBuild);
ps.Version = intMajor.ToString() + "." + intMinor.ToString() + "." + intBuild.ToString();
}
//Add each portal Tab to DekstopTabs
TabInfo portalTab = default(TabInfo);
ps.DesktopTabs = new ArrayList();
bool first = true;
foreach (KeyValuePair<int, TabInfo> tabPair in tc.GetTabsByPortal(ps.PortalId))
{
// clone the tab object ( to avoid creating an object reference to the data cache )
portalTab = tabPair.Value.Clone();
// set custom properties
if (portalTab.TabOrder == 0)
{
portalTab.TabOrder = 999;
}
if (DotNetNuke.Common.Utilities.Null.IsNull(portalTab.StartDate))
{
portalTab.StartDate = System.DateTime.MinValue;
}
if (DotNetNuke.Common.Utilities.Null.IsNull(portalTab.EndDate))
{
portalTab.EndDate = System.DateTime.MaxValue;
}
ps.DesktopTabs.Add(portalTab);
//assign the first 'normal' tab as the active tab - could be the home tab, if it
//still exists, or it will be after the admin tab(s)
if (first && (portalTab.TabID == portal.HomeTabId || portalTab.TabID > portal.AdminTabId))
{
ps.ActiveTab = portalTab;
first = false;
}
}
//last gasp chance in case active tab was not set
if (ps.ActiveTab == null) ps.ActiveTab = portalTab;
//Add each host Tab to DesktopTabs
TabInfo hostTab = default(TabInfo);
foreach (KeyValuePair<int, TabInfo> tabPair in tc.GetTabsByPortal(DotNetNuke.Common.Utilities.Null.NullInteger))
{
// clone the tab object ( to avoid creating an object reference to the data cache )
hostTab = tabPair.Value.Clone();
hostTab.PortalID = ps.PortalId;
hostTab.StartDate = System.DateTime.MinValue;
hostTab.EndDate = System.DateTime.MaxValue;
ps.DesktopTabs.Add(hostTab);
}
//now add the portal settings to the httpContext
if (System.Web.HttpContext.Current == null)
{
//if there is no HttpContext, then mock one up by creating a fake WorkerRequest
string appVirtualDir = DotNetNuke.Common.Globals.ApplicationPath;
string appPhysicalDir = AppDomain.CurrentDomain.BaseDirectory;
string page = ps.PortalAlias.HTTPAlias;
string query = string.Empty;
System.IO.TextWriter output = null;
//create a dummy simple worker request
System.Web.Hosting.SimpleWorkerRequest workerRequest = new System.Web.Hosting.SimpleWorkerRequest(page, query, output);
System.Web.HttpContext.Current = new System.Web.HttpContext(workerRequest);
}
//stash the portalSettings in the Context Items, where the rest of the DNN Code expects it to be
System.Web.HttpContext.Current.Items.Add("PortalSettings", ps);
return ps;
}
28 comment(s) so far...
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Hi I am using your code in my scheduler but it is giving me error at line Dim arrVersion() As String = DotNetNuke.Common.Assembly.glbAppVersion.Split(".")
I am running this in DNN 4.7
Do I have to add any other reference
Thanks
Jagdish
By jagdish on
Tuesday, January 20, 2009 11:53 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
@jagdish : that would depend on what the error was. You'll need a reference to the dotnetnuke dll.
By Bruce Chapman on
Wednesday, January 21, 2009 8:44 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Great article there Bruce. I was myself messing around with exactly that problem. Using the scheduler can sometimes be a nightmare. I have however made a similar fix for a client not too long ago. I found more or less the exact same solution.
However, what is your PortalId? and where do you get it from?
By Bo Stig Christensen on
Thursday, January 22, 2009 9:51 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Bo : glad to see I'm not the only one who found this problem and workaround. It must be at least partially the correct answer if more than one of us did it.
The portal id in this case comes from the database table used to manage the schedule queue. The scheduled task works through a set of stored emails and sends them : the portal Id is stored as part of that table, so the email knows which portal it belongs to. Assuming you've got something to work with (user, tab, etc) you should be able to work backwards to figure out what portal you should be dealing with.
By Bruce Chapman on
Thursday, January 22, 2009 11:22 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Thx for this post! needed a tiny bit of customisation but it definitly is a life saver.
By Maarten Hoekstra on
Wednesday, January 28, 2009 1:02 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
I am having something of a similar problem - at least in my head it is - we are trying to figure out if we can tell if a scheduked item is running and abort if it is - i personally cant tell right now but it seems there should be a way to do this
any thoughts
By Dylan Barber on
Saturday, February 07, 2009 5:03 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
@Dylan
You can inspect the schedulehistoryitem to determine if an item has been started but not stopped : however this may not give you any information on whether the thread for the scheduled item is still running. I'm not sure how you'd do that. I don't really think there would be a neat way to abort an already-running item. There's nothing in the event model to check for an abort condition. -Bruce
By Bruce Chapman on
Sunday, February 08, 2009 10:20 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Hi Bruce and thanks for the insight. I was pulling my hair out trying to figure out why I couldn't get a url to return. However, I'm having a little trouble using the method you supplied. When I try and build my project, I'm getting an HttpContext does not exist in the System.Web namespace? The intellisense for System.Web only shows AspHostingPermissions, AspHostingAttribute and AspHostingLevel and I don't know why.
Can you provide any guidance?
By Paul on
Saturday, February 14, 2009 5:12 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Sorry. I'm Dumb. I needed a reference to system.web. I was picking up some other system.web from a different namespace or something. Plesase disregard previous post and sorry to bother you with that.
By Paul on
Saturday, February 14, 2009 5:20 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
this is a great post! I was running into the same issues when writing custom scheduler client classes. thanks!
By kevin on
Wednesday, March 04, 2009 5:37 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Very nice job, thanks! Has anyone revised the code for dnn 5?
By Allen Foster on
Tuesday, March 10, 2009 6:05 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Hi Bruce,
I've just hit this - it was all going swimmingly well and I finally got localization, mulit-portals and scheduled item settings by portal working in my scheduled task... then I ran something through the Token Replacement stuff and yeah, it needs the PortalSettings.
Is this still the best way of assigning the PS to the current context? (DNN 4.9.2). I guess I'll have to do this tomorrow - thanks for sharing....
By Smart-Thinker on
Friday, May 22, 2009 11:05 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
As far as I know it's still the best way to create a portal settings instance. You can only store it in the Request.Context, so you've got to fudge that somehow.
By Bruce Chapman on
Saturday, May 23, 2009 8:21 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Ok, thanks, that worked well.
By Smart-Thinker on
Saturday, May 23, 2009 11:53 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Thanks Bruce,
Works fine, even 100% conversion in VB.
By David Lee on
Tuesday, July 07, 2009 5:10 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Looks like what I need to run my IFrame (I have a version that does encryption) and decrypt my encrypted querystring in the launched aspx.
But, I am wondering where to put this code, when to run it ?
(trying to use the Decrypt method from PortalSecurity, but I need some Portalsetting stuff in this launched thread).
Thanks for the code !
By iqworks on
Tuesday, October 06, 2009 11:59 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Great! It usefull to get all DNN functions like URL generation available from web-service !!! Thanks a lot...
By Bevz on
Saturday, December 19, 2009 3:48 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Hi Bruce,
Thanks for the article. The code really helped me to access portal settings object from web service. I wanted it for logging some event in event log from the web service. Only thing is, I had to store PortalId and UserId in JS variables so that I could pass it to the webservice. If you know any better way, can you please let me know.
Thanks & Regards, - Vivek Athalye
By Vivek Athalye on
Tuesday, December 22, 2009 11:56 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
I've simplified this code as much as possible, and can't understand the cause of the error. It runs fine, but I get the same error (object ref not set to instance...) in my dnn event viewer. The error shows up 3 separate times when I run (locally). Any ideas?
Namespace CORA.Modules.Members Public Class RenewalNotice Inherits DotNetNuke.Services.Scheduling.SchedulerClient
Public Sub New(ByVal objScheduleHistoryItem As DotNetNuke.Services.Scheduling.ScheduleHistoryItem) MyBase.New() Me.ScheduleHistoryItem = objScheduleHistoryItem End Sub Public Overrides Sub DoWork() Try Me.Progressing() DotNetNuke.Services.Mail.Mail.SendMail("omitted", "omitted", "", "testSubject", "testBody", "", "HTML", "", "", "", "") Me.ScheduleHistoryItem.AddLogNote("Renewal email sent: " & Date.Now().ToShortDateString) Me.ScheduleHistoryItem.Succeeded = True Catch ex As Exception Me.ScheduleHistoryItem.Succeeded = False Me.ScheduleHistoryItem.AddLogNote("Renewal email failed. " & ex.ToString) Me.Errored(ex) End Try End Sub End Class End Namespace
By Mike on
Saturday, December 26, 2009 3:53 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
@mike : you'll need to narrow down where in the code your error is coming from. The event viewer should give you an indication by giving you the namespace/component in the stack trace. From there, it's a case of working out what is 'not set' when the code runs. While your code looks OK, it's impossible to tell without tracing it through and finding out. You can also load up the debug version of the DNN framework, then run that (also set the compile=debug in the web.config). The stack trace will pinpoint the line in the code where the error is occuring, and from there you should be able to work backwards. There should be no problem with sending emails from a scheduler, but the scheduler can be tricky.
By Bruce Chapman on
Saturday, December 26, 2009 9:41 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
this solved my problem, but thanks for your help! www.snapsis.com/DotNetNuke/Support/tabid/560/aff/11/aft/5823/afv/topic/Default.aspx
By Mike on
Wednesday, December 30, 2009 2:14 AM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Hey Bruce,
Have you tested this code in DNN5.x? I am getting error in DNN 5.2.1:
When I tried to compile it says DesktopTabs property is ReadOnly.. just wondering if you've dealt with this before?
SmartThinker.DNN.Modules.League.LeagueScoreboardReportingTask, SmartThinker.DNN.Modules.League LeagueScoreboardReportingTask failed.System.MissingMethodException: Method not found: ‘Void DotNetNuke.Entities.Portals.PortalSettings.set_DesktopTabs(System.Collections.ArrayList)’. at SmartThinker.DNN.Modules.ModuleFramework.Business.League.Utilities.CreateNewPortalSettings(Int32 portalId, String preferredPortalAlias) at SmartThinker.DNN.Modules.League.LeagueScoreboardReportingTask.ProcessTask(String& auditTrail) at SmartThinker.DNN.Modules.League.LeagueScoreboardReportingTask.DoWork()
By Smart-Thinker on
Thursday, January 14, 2010 12:11 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
@rodney : no, I haven't tested it against 5.2.1. That does pose a problem, a read-only desktopTabs property. Just check to see that the DesktopTabs collection isn't already a valid object (ie, instantiated and perhaps count=0) - that way you wouldn't have to initialise it with the 'new' statement. You might be able to just start giving it tab objects.
By Bruce Chapman on
Thursday, January 14, 2010 1:05 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
Ok, it seems like a lot has changed in 5.x ;)
Some of the skinning stuff and the Desktop tabs. I didn't need any of this for my Scheduled task and I needed a quick fix so I got away with just commenting out the breaking changes. Some of the stuff was not even deprecated - it just no longer exists!
By Smart-Thinker on
Saturday, January 16, 2010 1:43 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item - v5.x
Hi all,
I am running DNN v5.6.1 and I simply can't get this PortalSettings to work out for me. I first tried to implement this to get the PortalSettings for Mail out, even cutting this down to just the necessary parts lead to so many issues. I have posted this on the DNN forums too - is moderated so will post link up here as soon as it is posted to DNN.
Cheers
C
By Craig Lambie on
Monday, March 21, 2011 3:41 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
DNN post for linkback www.dotnetnuke.com/Resources/Forums/tabid/795/forumid/203/postid/412111/scope/posts/Default.aspx#412111
By Craig Lambie on
Monday, March 21, 2011 6:55 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
@craig I haven't yet tried this for 5.5+. The basic structure should be OK but some things might have changed.
By Bruce Chapman on
Tuesday, March 22, 2011 1:51 PM
|
Re: Creating PortalSettings Instance running in a DotNetNuke Schedule Item
hello . I come from china. I want Adding NavigateURL in skin?
By panfeihu on
Thursday, December 15, 2011 12:45 PM
|