If you have heard or used DotNetNuke and built some modules to it, you might be aware of the fact that as in web development, usually, building small and quick functionalities into a website usually requires a ton of coding with quirky (and usually pricy) IDEs. Just came up with an idea while thinking of building another module for creating macros inside DotNetNuke: hey, why don't we all use scripting?
Ok, nowadays everything is scripted - even parts of Operating Systems are scripted. As the speed and memory of computers keep getting bigger, it actually doesn't matter that much since with different kinds of scripting languages, we get easy and yet powerful access to various down-level functionalities that would otherwise require rather extensive knowledge on various technologies. With this in mind, I didn't think it would be a bad idea to run an interpreted language inside another interpreted language.
You only need .NET 2.0 and DotNetNuke 4.x running on the website - .NET 2.0 is required by IronPython and thus the DotNetNuke 4.x. I'd love to see this working in .NET 1.1 and DotNetNuke 3.x, but unfortunately, IronPython relies heavily on Generics and can't be translated easily to .NET 1.1.
How it works
The basic idea is that we have the DotNetNuke portal installed where we run various modules that are actually quite independent pieces of software that rely on the DotNetNuke core framework. Also, the IronPython module (still a working name) is a normal module that actually embeds the IronPython running engine inside the module that runs inside the DotNetNuke ASP.NET application, which runs inside IIS's worker process. This allows developers to quickly run small (or even larger) Python scripts inside the module while still having total control over the current module's functions, DotNetNuke portal's or host's functions, and even the ASP.NET application's functions. This is done by providing the following modules, objects, and namespaces by default after initializing the actual Python engine:
- App - This is an ASP.NET application object that contains DotNetNuke. With this, you can directly access normal ASP.NET objects like
Response etc. Other application specific items are also available; just type "dir(App)" to see them all.
- DotNetNuke - OK, this is obvious. This object provides all the information about running a DotNetNuke instance with all area access to Users, Tabs/Pages, Portals etc. Just fool around to see what you can find.
- Handler - This one is an object of "
Web.HttpContext.Current.CurrentHandler" that contains, as it says, the HttpContext's current handler. At the moment, I have no idea where to use this, but give me a hint if you get it. Just imported for total access.
- Page - This one gives the user raw access to the ASP.NET page - yes, ASP.NET page, not DotNetNuke's Tab/Page object. You can also access this from "
- Web - This is a shortcut to the
System.Web namespace from the .NET Base Class Library. For some reason, the
Web namespace doesn't load automatically although the IronPython engine is run under the ASP.NET application, but the
System.Web namespace has to be located in the code-behind file by calling "
System.Reflection.Assembly.GetCallingAssembly". Doesn't matter - works this way as well.
Then a few objects that are more interesting:
- Module - This is the actual module inside which we are running the IronPython engine. All DotNetNuke PortalModuleBase functionalities are available.
- IronCanvas - OK, now we are getting somewhere - probably the most interesting object. This is a normal
PlaceHolder control where we can drop in other ASP.NET or DotNetNuke controls.
These are the basic modules and objects that are set up for developers to tweak around to see how things work. I'm not that good yet with Python, so I just threw in a few small code samples that will give you a raw idea of what we are talking about.
Here's one small script that allows you to list all the users in DotNetNuke:
uc = DotNetNuke.Entities.Users.UserController()
users = uc.GetUsers(False,False)
for n in users : print n.FullName + " = " + n.Username
print "\nUsers in system : "
And here's another that lists all the pages (including the Admin and Host pages):
tc = DotNetNuke.Entities.Tabs.TabController()
tabs = tc.GetAllTabs()
for t in tabs : print t.TabName
Get the idea? You can also write directly to the response stream with the following statement:
The following redirects the user's browser:
Writing running scripts
With the current version of the module, you have two options: you can either work around with the IronPython Console, or you can set up a script that is run every time the module is loaded. This means that you can restrict the module's running rights with normal DotNetNuke role based security settings. At the moment, writing out the Python script is not as easy as it should be, but probably, future versions will have a better working editor. At the moment, you can access the simple editor by selecting "Settings" from the module's dropdown menu. From there, you should see "IronPython Settings" in the bottom of the Settings section. After opening it, you will see a simple textbox that allows you to write your own code. For starters, put a script like this there:
cal = Web.UI.WebControls.Calendar()
Don't check "Keep IronPython engine in user session..." since this seems to have funky results at the moment. After clicking "Update", you should see a simple ASP.NET calendar control inside the module. Reading the small code should give you the hang of it. Note! At the moment, there is no solution to handle the events inside ASP.NET or UserControls, so please check for further betas in case you find this interesting. There is a "
pyevent" module available for you to import, but while writing this, I haven't got the idea of how to create a function that responds to the events of ASP.NET controls - this might be because of the beta (6) phase of IronPython or the actual fact that IronPython is not designed for environments like ASP.NET.
Naturally, you can also put to script input one (or both) of the previous scripts - just to see how they work.
Maybe this is enough this time - give me feedback, ideas, and correct me if something here is badly wrong. Hopefully, once our module's version 1.0 is released, IronPython would be in its final release as well so that we can get all the cool modules that can be found in "legacy" Python.