Simon
If you're writing code, the actual call you're looking for is the 'DotNetNuke.Common.Globals.NavigateUrl()' call.
There are several overloads for this:
(1) NavigateUrl() : generates a url for the current tab (as defined by the current request)
(2) NavigateUrl(int tabId) : generates a url for the supplied tabId
(3) NavigateUrl(string controlKey) : generates a url for the current tab, and the specified control key. The control key being the <key> element as defined in the module manifest file, and the module definition. Typically, this call is used for generating 'Edit' urls, although 'EditUrl()' will do the same thing.
(4) NavigateUrl(int tabId, bool isSuperTab) : generates a url for the specified tab, and optionally allows specification that it is a 'super' tab. The superTab switch allows the system to decide what format to present the 'admin' tabs in - generally you don't genereate 'friendly' urls for the 'super' tabs.
(5) NavigateUrl(int tabId, string controlKey) : generates a url for the speciifed tab, and the specified control key. A combinatoin of (2) and (3). Used for generating a link to a non-default view of a module control on another tab.
(6) NavigateUrl(string controlKey, params string[] additionalParameters) : generates a url for the current tab, including the control key and a set of optional query string parameters. Used for generating a url for a tab where query string parameters are to be used as well. The params string can be supplied like this : "key=value". This will output either key=value or /key/value depending on the friendly url settings. If the Url is for the default 'view' control, pass in ControlKey="".
(7) NavigateUrl(int tabId, string controlKey,params string[] additionalParameters) : as with (6) only with a different tabId supplied - generates the url for a tab other than the current tab.
(8) NavigateUrl(int tabid, PortalSettings settings, string controlKey, params string[] additionalParameters) : as with (7), 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.
(9) NavigateUrl(int tabId, bool isSuperTab, PortalSettings setting, string controlKey, params string[] additionalParameters) : as with (8) but with the 'isSuperTab' switch, as described in (4).
(10) NavigateUrl(int tabid, bool isSuperTab, PortalSettings settings, string controlKye, string language, params string{} additionalParameters) : the full enchilada : you can specify all settings in (9) but also supply the language of the url. This will insert the /language/en-Us/ parameter into the url, depending on the language and friendly url settings.
Now, the actual output of the NavigateUrl call not only depends on the overload you choose (and the parameters you pass) but also the friendly url settings. At the top level of the friendly url settings, there is the on/off switch in host settings. There's also the 'urlformat' attribute in the web.config, and finally you can implement a totally different friendly url provider like one of the ones I build and distribute, which will give more friendly urls, but not at the expense of ignoring the DNN API.
The problem with trying to format up the url yourself in code such as you described is that it doesn't take into account many of the different options and settings that are inherent in the Url scheme for DNN, such as language, current portal alias, control keys and whether or not the tab is an admin tab. No DNN module developers should *ever* format up their Urls in this manner, because it will mean your module will always cause bugs for people now (who run different settings like languages etc) and in the future (when/if the DNN core decides to make an adjustment to the url scheme).
You might also like to read these blog entries of mine which deal with the subject matter in more depth:
An open letter to the DOtNetNuke developers of the workd : Please start using the FriendlyUrlProvider API for custom page names! and Designing, Structuring and Architecting DotNetNuke Modules. These cover the relationship of the DNN Manifest file entries to the urls and design of your modules, and cover generating friendly urls through better use of the FriendlyUrl API.
Understanding Urls is the key to good DNN module development - so taking the time to properly understand DNN Urls will pay off for you.
-Bruce