Displaying User Profile photos in other places (with a little help)

Today I ran into a problem I didn't imagine still existed (in DNN v.7.2). I was using Ventrian Property Agent and I needed to display the profile photo of the user who made the submission inside the module's View Item template. I was surprised that neither Property Agent supported that, nor was there another way to get the user's profile image at a decent size inside the module's templates.


I'm sure that even if you aren't using this specific module, you've also ran into this issue one way or another. There is no decent built-in way to display a user's profile image outside of the user profile page itself.


In my case, there is a token Ventrian Property Agent users named [USERID] that provides the id of the user who has created the current entry. With only this in hand, I had to find a way to use it to get a decent profile picture.


First option would be to use the standard DNN /profilepic.ashx image handler, but this one returns distorted, grainy images of max 64x64 pixels. Using it like this: <img src="/profilepic.ashx?userid=[USERID]"> would give me a crappy image, but at least an image.


Two minutes before I was ready to give up, I ran into this gem: http://bbimagehandler.codeplex.com/ - this is a generic image handler that does a lot of things - resizing, watermarks, etc. but one interesting feature is that it can render DNN user profile images - in any dimension given, and with awesome quality compared to DNN's own profilepic.ashx.


Give it a try if you're facing the same problem. Have in mind that in order for DNN Profile Pictures to work, you'll HAVE to specify the "db" parameter as mentioned in the documentation. By specifying this parameter, it is implied that you have already updated your web.config file with this key:


<add key ="BBDatabase" value="Connectionstring=SiteSqlServer;table=MyImages;ImageField=ImageData;idField=ImageID" />


The trick is that you only need the first part if you only need BBImageHandler to handle profile images, since it already knows what tables and fields to use. So you can use this version:


<add key ="BBDatabase" value ="Connectionstring=SiteSqlServer;" />


Where "SiteSqlServer" is your connection string's name (in case you have renamed it from the default name DNN gives it).


This way, it is only enough to know the user id whose profile image you need to show - In my case, as I said above, I had the [USERID] token, so my code was as follows:


<img src="/bbimagehandler.ashx?db=BBDatabase&userid=[USERID]&portalid=0&width=300">


And voila! A profile image with a 300px width inside a Property Agent Template! (I'm thinking of even using it inside the user profile page itself).


Until next time!



Customizing DNN 7 Search and Search Results

DNN 7 has introduced a new, Lucene-powered indexing and search results retrieval mechanism. This means that all techniques you knew are not in effect any more. No more SQL queries and/or tables, data get returned in JSON format and rendered via Javascript. For more details, please read this post on DNNSofware.com


This adds a whole lot of new functionality but also a lot of limitations in the way Search Results are presented. Actually, there never was a straightforward way to customize Search Results, but until now you could just edit SearchResults.ascx and its corresponding code-behind file and have your desired result.


Things are still ugly regarding customization. The default Search Results layout includes a link guiding you to advanced search concepts, an "Advanced" form that asks you to provide various information such as where you want to search (categorized by module type) and so forth.


This doesn't always make sense to end users, and some elements have to be removed in specific scenarios. Users don't always want advanced search options, nor do they need to know what type of modules your site contains. In some cases they don't give a damn about the author, or the last modified date too. But there's no immediate way to configure what will be displayed and what will be not.


Moreover, until now you could face the problem of default module titles (which users usually leave as is because they are using containers that didn't include the module title) by tweaking the way module titles were inserted in the SearchItem table (see this older post for more). Since no SQL tables are used any more, you're left with ugly "Text/HTML" and other default titles in Search Results. The JSON returned for each search result item just contains a title that is often made of a concatenation of the tab's name and the module's title (or, in the case of grouped results, just the module's title).


Moreover, having a module with a BLANK title is no longer an option since modules with blank titles are not indexed(!). For more info, see my question here: http://www.dnnsoftware.com/answers/cid/420779


So le't see how we can address all of the above with some modifications on specific files. Be warned that what I'm saying here applies to version 7.1 and may or may not be in effect for future DNN versions, as well as that those changes are not upgrade-proof, meaning that if you upgrade your site to a higher DNN version you may lose them. But, it's better than nothing. :)


Be sure to get a backup of all the files you are going to modify in case something goes wrong!


Let's start.


Hiding the "advanced" link

File: dnn.SearchResult.js

Location: DesktopModules\Admin\SearchResults


Go to line 343, you will see a call to the DnnSearchBox like the following

      dnn.searchResult.searchInput = $('#dnnSearchResult_dnnSearchBox').dnnSearchBox({
           id: 'dnnSearchResult_dnnSearchBox',
           filterText: dnn.searchResult.defaultSettings.advancedText,
           showAdvanced: true,
           advancedId: 'dnnSearchResultAdvancedForm',



Locate this line:

showAdvanced: true,


And change it to

showAdvanced: false,


This is an option that you can't access via the module settings and it hides the "advanced" link. Unfortunately, the form that would pop up will still be visible at the bottom of the page so you have to take an extra step:


File: SearchResults.ascx

Location: DesktopModules\Admin\SearchResults


Go to around line 55 and you'll see a DIV element surrounding the elements of the Advanced form, like the following:

<div id="dnnSearchResultAdvancedForm" class="dnnForm">
    <div class="dnnFormItem">
        <dnn:Label ID="lblAdvancedTags" runat="server" ResourceKey="lblAdvancedTags" />
        <input type="text" id="advancedTagsCtrl" />
    <div class="dnnFormItem">


Add a style="display:none;" attribute to the outer div to hide the whole form.


If you need the advanced form but do not need to show specific controls, you can just skip the steps above, go at this point and just add a style="display:none;" attribute to any of the DIVs nested inside to hide the specific control you don't need (e.g. Scope)


Hide Advanced Tips link


File: dnn.SearchResult.js

Location: DesktopModules\Admin\SearchResults


Go to line 359 (it's empty), just above this piece of code:

$('a.dnnSearchResultAdvancedTip').on('click', function () {
            return false;

And insert the following line:



Alternatively, you can achieve the same result by adding a style="display:none;" attribute at the A tag in SearchResults.ascx, line 6:

<a href="javascript:void(0)" class="dnnSearchResultAdvancedTip"><%= LinkAdvancedTipText %></a>


Hide Results by Page / Sort section


File: SearchResults.ascx

Location: DesktopModules\Admin\SearchResults


Go to line 13 and add a style="display:none;" attribute to the outer DIV element there (first element in code snippet below):

<div class="dnnSearchResultPanel">
    <div class="dnnRight">
        <ul class="dnnSearchResultSortOptions">
            <li class="active"><a href="#byRelevance"><%= RelevanceText %></a></li>
            <li><a href="#byDate"><%= DateText %></a></li>...


If you hide this section but you need to specify a different sort order and/or results per page setting, you can alter the Javascript call at the same file, line 116 onwards, by altering the sortOption and pageSize initial values:

$(function () {
        if(typeof dnn != 'undefined' && dnn.searchResult){
            dnn.searchResult.moduleId = <%= ModuleId %>;
            dnn.searchResult.queryOptions = {
                searchTerm: '<%= SearchTerm %>',
                sortOption: 0,
                pageIndex: 1,
                pageSize: 15

sortOption can be 0 for date, 1 for relevance.

pageSize can be anything you need.


Hide various elements on Search Results


Well, some people don't like the "last updated" information. Others don't like the "author" info. So let's see how we get rid of anything we don't need:


File: dnn.SearchResult.js

Location: DesktopModules\Admin\SearchResults


Start from about line 112,where you'll see code like this:

markup += '<div class="dnnSearchResultItem-Others">';
        markup += '<span>' + dnn.searchResult.defaultSettings.lastModifiedText + ' </span>';
        markup += data.DisplayModifiedTime;
        markup += '</div>';

        markup += '<div class="dnnSearchResultItem-Others">';
        markup += '<span>' + dnn.searchResult.defaultSettings.sourceText + ' </span>';

Comment lines 112 to 115 to get rid of the "last updated" text

Comment lines 117 to 119 to get rid of the "source" text and link

Comment lines 121 to 123 to get rid of author info

Comment lines 126 to 135 to get rid of 'tags" info


Hide default HTML module titles (if any)


As mentioned earlier, you may not want module titles to appear in search results, but they do, even if your container doesn't display the module's title. The most common is "Text/HTML" and we'll see how to get rid of it in Search Results.


File: dnn.SearchResult.js

Location: DesktopModules\Admin\SearchResults


Scroll down to the bottom of the file and append this function at the end:

function fixTitle (s) {
    if (s=='Text/HTML') {
        return ('...');
    var s1;
    var s2;
    s2=s.substring(s.indexOf('>')+2, s.length);
    if (s2=='Text/HTML' || s2==s1) {
        return (s1);
        return (s);

This function accepts a search result item title and first checks if the title is "Text/HTML". If so, it returns three dots ("...") instead. You will find this in grouped results, where the module title is displayed on its own.


If the title does not belong to a group subset, it'll be in the format "xxx > yyy" where xxx is the page's name and yyy is the module's title. The code breaks the string in its two parts and checks if the second part is equal to "Text/HTML". If so, it returns only the first part (the page's name). Also, if both parts are the same it once more returns the first part. Useful when a module has the same title as the page and you don't want to see this in search results.


This is not the best possible solution, but it's a decent workaround, provided that you don't have the character ">" anywhere in your module titles or page names. I know it can get better, but this is only to demonstrate how you can do it.


In order to put our function into effect, we have to go to line 107:

markup += '<a href="' + data.DocumentUrl + '"' + dnn.searchResult.defaultSettings.linkTarget + '>' + data.Title + '</a></div>';

and replace data.Title with fixTitle(data.Title):

markup += '<a href="' + data.DocumentUrl + '"' + dnn.searchResult.defaultSettings.linkTarget + '>' + fixTitle(data.Title) + '</a></div>';

Hide subsets (grouped results)

If, for some reason, you don't want to have any grouped results then you can comment out the code that is generating them. Be adviced that the result that was supposed to be grouped won't display a description underneath, just the title and link.


File: dnn.SearchResult.js

Location: DesktopModules\Admin\SearchResults


Go to line 159 and comment the code there until line 161:

// render subsets
                   for (var j = 0; j < result.Results.length; j++) {
                       markup += '<div class="dnnSearchResultItem-Subset">' + dnn.searchResult.renderResult(result.Results[j]) + '</div>';


Finally, if you tamper with the way search results are rendered, you may not want to have auto-search (search-as-you-type) get in your way by rendering everything in a different way (e.g. using default text/html module titles). There is no option for disabling it, but we can always hack the code a little more:


File: SearchSkinObjectPreview.js

Location: Resources\search


Go to line 137 and comment out this piece of code (until line 155):

throttle = setTimeout(function() {
                         var service = $.dnnSF ? $.dnnSF(-1) : null;
                         var url = makeUrl(val, service);
                         if (url) {
                                 url: url,
                                 beforeSend: service ? service.setModuleHeaders : null,
                                 success: function(result) {
                                     if (result)
                                 error: function() {
                                 type: 'GET',
                                 dataType: 'json',
                                 contentType: "application/json"
                     }, self.settings.delayTriggerAutoSearch);

This will prevent the Search skin object from auto-searching.


Well, that's all! Even if line numbers change with an upgrade, you have a reference point on what to seek in code. I know this is not the prettiest or the most accurate and bullet-proof solution in the world, but until DNN Corp. decides to add more configuration settings to its Search subsystem, it will have to do. In the meantime, you can vote for my relevant suggestion in Community Voice here:



Oh, and please feel free to suggest any other improvements / hacks to Search and Search Results! I know I didn't cover the whole range of possible modifications, but these are, IMHO, the most common ones.


Until next time!



DNN Sharp's My Tokens 30% off (until 7/26/2013)

da12dcee5605e1fa99b50d8b9401aedcDNN Sharp are promoting a discount on their popular My Tokens module that will expire on the 26th of July, 2013. To get the discount, you have to buy their Action Form module from the DNN Store.


Action Form is a form builder module which lets you create complex forms quickly and save data to the database / send emails etc. on submission.


My Tokens is a module which lets you include dynamic content from database or HTTP requests in static content.It works with a number of DNN modules out of the box (including Text/HTML and Form and List) but you can even patch the DNN core (with instructions) to extend support to every installed module.



Buy Action Form here

Buy My Tokens here



25% off all Data Springs products (until 7/23/2013)

logoData Springs is taking 25% off all its products until Tuesday, 7/23/2013. You can order your products from the DNN Store and use the promo code BYEANNIE on checkout to get a 25% discount.


If you don't know Data Springs' modules, you should give it a look - their flagship products are Dynamic Forms, Dynamic Registration and Dynamic Login, and there are more than a dozen more. There is also a bundle named Data Springs Collection for a very low price compared to bying the products one by one.



At last! DNN7.1 has extensionless URLs and a "url name" setting for every page

This is a big step forward. Starting with DNN v.7.1, you can say goodbye to ugly URLs and .aspx extensions. Following a suggestion made by yours truly (here: http://www.dnnsoftware.com/voice/cid/138237), DNN 7.1 has adopted a "Page URL" field in Page Settings, letting you specify the exact URL the page should use.


My Website   About Us   StyleAndGuide


This is essentially an URL rewrite for the page, that makes the page's URL independent of the page's name, meaning that you can change the name as many times as you like, without affecting any links that are present in text/html modules or elsewhere.


The only bad thing (or good, depending on your point of view) is that the URL is not automatically synthesized based on page hierarhcy, meaning that you have to specify the exact URL for each page, starting from the virtual root.


For example, in the default DNN installation you have the About Us page which has a URL of "/About-Us" while the sub-page Style Guide has a URL of "/About-Us/StyleGuide". The whole URL for the Style Guide page has to be typed again, i.e. the "/About-Us" part is not inherited from the URL field of the parent page.


This makes things a bit more difficult since you have to remember the URLs of parent pages if you want to represent the hierarchy using friendly URLs, but on the other hand gives you a bit of freedom since you do not need to specify exact paths to get to a page - you can easily give the Style Guide page, for example, a URL of "/YourStyleGuide", forgetting the "About-Us" part at all.


It would be nice to see an "inherit" option in future versions though.



Bug: "Redirect after login" not redirecting to localized versions of page

I am currently working on DNN7, on a multilingual site (4 languages). The site has public registration and users must be redirected to a specific page after they complete their registration.


I found that DNN would not let me specify a different page for every language - in fact, if I went to Admin -> Site Settings -> User Account Settings -> Login Settings -> Redirect after Registration and selected a specific page in one language, it would give me <None Specified> if I went to the setting using another language.


This would probably have no impact if DNN took care to redirect the user to the localized version of the page after registration - which it doesn't (at least until version 7.0.6). So I had to alter a few things, which I'd like to share with you in case you are facing the same problem.


The problem seems to be on the \DesktopModules\Admin\Security\Register.ascx.cs file, which fortunately can be directly edited so no recompilation is needed. If you go to line 162 there, (the "else" portion of a rather large if statement), you'll see that it does the following:


_RedirectURL =



Where "setting" is the Tab ID of the tab you have selected on the Site Settings section for redirecting after registration. This, of course, is not localized so it'll always take you the the actual page you have specified - regardless of the actual language the user is using to register.


In order to fix this, I copied and adapted some code from the language skin object (yes, the language picker) which can always find the right localized version of a page. So here's what I did:


I changed the line:


_RedirectURL =





int currentPortal =


Locale currentLocale =

LocaleController.Instance.GetCurrentLocale (currentPortal);

TabInfo localizedTab =

new TabController().GetTabByCulture(

Convert.ToInt32(setting), currentPortal, currentLocale);

_RedirectURL = Globals.NavigateURL(



And I also had to add two usings on top of the page:


using DotNetNuke.Entities.Tabs;
using DotNetNuke.Entities.Portals;

With those changes, I managed to have the page to redirect to specified only once and have DNN redirect me to the page's localized version depending on the language I used to register.


Also please see here: http://support.dotnetnuke.com/project/All/2/item/26617 for other issues with Redirect after Login functionality. I applied the change to line 136 of the file mentioned in this issue, too.


One caveat: If you upgrade your DNN installation, you will probably lose those changes.


Also, have in mind that the same thing probably applies to the "Redirect after Login" functionality - I'll probably post something similar about that soon :). Plus, I have also created an SQL-based adaptation of GetTabByCulture to be used with OWS - I hope I have enough time to post this here too.


Standard disclaimer: Keep a backup of your initial Register.ascx.cs file. Don't blame me if this doesn't work for you. This is a solution that worked for my own project and it's not guaranteed to work in every case. Did I mention backup?


Until next time!



Great news on Open Web Studio (OWS)!



If you are using DNN, I'm sure you have at least heard of Open Web Studio, (OWS), a RAD development platform for DNN that is open source, free, and lets you create things for which you would otherwise need full-blown module development. For example: Database - bound grids, forms, queries and templates to view results, AJAX calls, conditional display of information and much more.


In the past few years, OWS has been stuck to version 2, with frequent updates including updates for working with DNN 7, but no new functionality. Although the community is very active, documentation is still lacking and many people keep asking about the future of OWS, worrying that it may be (or has already been) abandoned.


I had a recent chat with Kevin Schreiner, the lead developer for OWS, and with his permission I'm copying here his thoughts and plans on OWS. If you don't want to read all of it, bottom line is that Kevin is actively supporting OWS and preparing for OWS 3!


Here's what I asked, among other things:


I am curious (just as so many people) to learn news about OWS's future (if such a future exists). I've used it so much I have lost count - and I'm eager to see it evolve. As far as I understand, you're (or were) the only developer maintaining it. Should I keep my hopes up high or go desperate? :)


And here's Kevin's reply:


No worries, I understand the anxiety. I created ListX which became OWS while working for Bi4ce - which became R2integrated, and I'm still the only developer maintaining it. This shouldnt be a cause for concern. I've been holding off on releasing OWS3 due to a myriad of complications revolving around the changes to the DNN platform and adjustments to the core libraries needed for the new UI all while keeping the platform releases for OWS2 still working within the latest DNN versions. The issues with the OWS3 UI stem from the fact that DNN which typically struggles to release ANYTHING on newly released technologies, adopted the latest jQuery version in the DNN7 release. Doing this caused the UI Layout Manager plugin which I was relying on for the OWS3 release to malfunction and I've had to resort to building a new logical structure for handling it. Plus, there have been some issues with the logic in use of the UI because it has been confusing while working within multiple configurations and multiple actions simultaneously. You can see from the original comps how this could be confusing, because when you have more than 1 action opened, you dont know which action is linked to which configuration.

Hopefully something that should make the community rest easily, I rely on OWS for 99.9% of my own livelihood, using it as my core development platform, extending its core functionality and keeping it up to date for the latest DNN releases. Obviously, this being the fact means that OWS isnt going anywhere ;)  (...) Once I feel comfortable with the OWS3 release stability, I will most assuredly release it to the general public. It has always been and will always be primary in my focus to release something that is solid and stable as it is so important to all of our runtimes.


In the meantime, rest assured that nothing is going to happen to my baby :) It's a labor of love, and something that I personally rely on.


I am extremely happy with his answer! What about you?

Related Posts with Thumbnails

Recent Comments

Free DotNetNuke Stuff

Free DotNet Videos

  © Blogger template The Professional Template by Ourblogtemplates.com 2008

Back to TOP