Testing an implementation of the DNN ISearchable interface implementation for a module can be time-consuming and slow if you rely on the DNN search engine indexer to run and then either check the database for results or use the Search UI. There is a simpler way.

Copy and paste the below script into DNNSearch.aspx (or grab the attachment at the end of this post), place the file in the root folder of your app and you can test ISearchable for any module instance with ease. The script requires you to provide a TabId and a ModuleId. It then queries the database for the BusinessController defined in the DesktopModules table and instantiates it exactly as the DNN search indexer does. It then calls GetSearchItems() and displays the results.

Unlike the DNN search indexer, DNNSearch does not make any changes to the database. It is useful only for testing if the ISearchable implementation is working correctly and does not provide any insights into any issues that the search index provider you are using may have.

 

DNNSearch.aspx

<%@ Import namespace="DotNetNuke.Entities.Modules" %>
<%@ Import namespace="DotNetNuke.Services.Search" %>
<%@ Import namespace="DotNetNuke.Common" %>
<%@ Page Language="c#" AutoEventWireup="false" %>
<script runat="server">
 
    void Results_Click(object sender, EventArgs e)
    {
        int moduleId = -1;
        try
        {
            moduleId = Convert.ToInt32(ModuleId.Text);
        }
        catch
        {
        }
 
        int tabId = -1;
        try
        {
            tabId = Convert.ToInt32(TabId.Text);
        }
        catch
        {
        }
 
        if ((moduleId > -1) && (tabId > -1))
            GetSearchResults(moduleId, tabId);
        else
            SearchResults.Text = "Both Module ID and Tab ID are required";
    }
 
    void GetSearchResults(int moduleId, int tabId)
    {
        ModuleController moduleController = new ModuleController();
        ModuleInfo moduleInfo = moduleController.GetModule(moduleId, tabId);
        StringBuilder sb = new StringBuilder();
 
        if (moduleInfo == null) 
        {
            SearchResults.Text = "No module found with ModuleID=" + moduleId.ToString() + " and TabID=" + tabId.ToString();
            return;
        }
 
        if (moduleInfo.BusinessControllerClass == "")
            SearchResults.Text = "The BusinessControllerClass in the database is blank.";
        else
        {
            try
            {
                object bizController = DotNetNuke.Framework.Reflection.CreateObject(moduleInfo.BusinessControllerClass, moduleInfo.BusinessControllerClass);
                if (bizController == null)
                    SearchResults.Text = "The Business Controller Class " + moduleInfo.BusinessControllerClass + " could not be instantiated.";
                else
                {    
                    SearchContentModuleInfo contentInfo = new SearchContentModuleInfo();
                    contentInfo.ModControllerType = (ISearchable) bizController;
                    contentInfo.ModInfo = moduleInfo;
                    SearchItemInfoCollection results = contentInfo.ModControllerType.GetSearchItems(contentInfo.ModInfo);
                    if (results != null)
                    {
                        int counter = 0;
                        foreach(SearchItemInfo searchItem in results)
                        {
                    if (moduleInfo.ModuleID == searchItem.ModuleId)
                    {
                        sb.Append("

Title: " + searchItem.Title);
                        sb.Append("GUID: " + searchItem.GUID);
                        sb.Append("Date: " + searchItem.PubDate.ToLongDateString());
                        sb.Append("Description: " + searchItem.Description + "

");
                    }
                    counter++;
                        }
                        SearchResults.Text = counter.ToString() + " results found." + sb.ToString();
                    }
                    else
                        SearchResults.Text = "No search results.";
                }
            }
            catch(Exception e)
            {
                SearchResults.Text = "Error: " + e.Message + "

" + e.StackTrace;
            }
        }
    }
 
    override protected void OnInit(EventArgs e)
    {
        Results.Click += new EventHandler(Results_Click);
        base.OnInit(e);
    }
 
script>
 
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
    <HEAD>
        <title>Speerio ISearchable Testtitle>
        <style>
              body, p {font-family: Verdana; font-size: 9pt}
        style>
    HEAD>
    <body>
        <p><font size="4">DNNSearch Script - by <a href="http://www.speerio.net">Speerio, Inc.a>p>
        <p><font color="red" size="4">WARNING: Do not leave this script installed on a production system.font>p>
        <form id="Form1" method="post" runat="server">
            <p>Tab ID: <asp:TextBox ID="TabId" Runat="server">asp:TextBox>p>
            <p>Module ID: <asp:TextBox ID="ModuleId" Runat="server">asp:TextBox>p>
            <asp:Button ID="Results" Runat="server" Text="Get Search Results" />p>
            <p>To test for user-specific results, add code to GetSearchItems() to check for userid=N in querystring.p>
            <p><b>Search Results:b>p>
            <asp:Label ID="SearchResults" Runat="server" />
        form>
    body>
HTML>

DNNSearch.zip (1.48 KB)

Wouldn’t you know it…I post a spoof about Web 2.0 Design Guidelines and the very next day discover a site that dynamically generates Web 2.0 logos. Here’s the devTao Web 2.0 logo rendered by the site:

 

Get your own Web 2.0 logo here: http://msig.info/web2.php

Note to startups — When coming-up with marketing language for your site, pay attention or you will end-up with self-fulfilling prophecies. “Kiko is a great, dead simple calendar” might not have been the most appropriate choice of words for Kiko.

On the DotNetNuke forums today, jstemper posed a question about how to speed up DNN development, specifically, the delay caused by app re-start when a module is recompiled.

I have invested a considerable amount of time researching the intricacies of Fusion probing to faciliate the co-existence of third-party assemblies with different versions in the same bin folder. In an earlier post on Managing assembly versions in ASP.Net I had provided tips on doing this. Reading this post got me thinking about applying the same technique for DNN development. I did a quick test and everything seems to work. Here is how you can speed-up DNN module development by skipping the app restart that occurs when assemblies in the “bin” folder are updated.

1) Create a “bin” folder under ~/DesktopModules (i.e. ~/DesktopModules/bin)

2) Modify your DNN web.config as follows:

            <runtime>
              <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                   <probing privatePath="bin;DesktopModules\bin" />
              assemblyBinding>
           runtime>

If you have a section already present, just add the element, otherwise, you can just add this whole block right before .

The “privatePath” attribute tells Fusion where to search for assemblies referenced by an application.

3) Change your module’s script (ascx) file so the “Inherits” attribute includes the assembly name like this:

Inherits=”Speerio.DNN.Modules.SkinStudio.Editor, Speerio.DNN.Modules.SkinStudio”

This corresponds to a typename of “Speerio.DNN.Modules.SkinStudio.Editor” and an assembly file “Speerio.DNN.Modules.SkinStudio.dll” (note: the extension should not be included in the “Inherits” attribute value).

4) Change your module’s VS.Net project build folder to ~/DesktopModules/bin

That’s it. Now, when you recompile your module, there will be no application restart and the only assemblies that are converted from bytecode to native code are your module assemblies.

Please post a comment if you encounter any problems so I can modify the procedure if necessary.

If you want your website to be Web 2.0–worthy, there are some guidelines you can/should follow to ensure that your site visitors will instantly develop an appreciation for your insightful design and ability to stay current. Here is a partial list:

1) Markup: Ensure that your site’s markup is XHTML 1.0 Strict standards-compliant. For bonus points, place appropriate chiclets at the bottom so visitors know that you are a CSS God and should they wish to examine the source code, they will not find any ugly

tags. (In case you missed the memo, having a
tag on your site is the sure-fire path to ruin for your business since most users look for this and shun businesses that use this tag in their HTML markup.)

2) Gradients: I cannot stress how important this is — use gradients for all background and buttons. Without them, your site will look pathetic and laughable. If you can, try and include gradients in headers of sections within your site. If you really want to be hip, add a pattern of angled lines. Be careful with this one…an angle of 15–25 degrees is considered cool. Any more and you risk turning-off users.

3)  Lists: Use HTML lists for organizing as much content as possible. By using

    and
  • tags combined with style classes, you can make information that would have been very difficult to comprehend in
tags, much, much easier to comprehend. When defining the style classes for the list elements, try and include as many CSS hacks as possible. Sure, this makes your site work in all browsers, but most importantly, it conveys your commitment to customer satisfaction. It shows how you will go out of your way to ensure that the three users visiting your site with the WallyWollaWidget Browser v0.5 alpha also have a fantastic user experience and, of-course, ease of content comprehension.

4) AJAX: Do a search-and-replace of all site content and change all occurrences of “XMLHttp” with “AJAX.” If your search does not return any results, then you have a serious problem. Immediately edit content to ensure that there are at least 3–4 references to AJAX on each page. If you have the time, add functionality that allows users to drag things around the page. This will keep them occupied and if you don’t have any meaningful content on the site, it will convince them that your site is a must-bookmark anyway.

5) Soft lines: Thoroughly check your site to ensure that there are no unsightly dark lines. Change the color of all lines to light grey. If possible, ensure that one end of each line fades into the background. Dark lines have been known to cause problems with content flow. By using light grey lines, you can be assured that your site visitors will not lose their train of thought between paragraphs.

6) Rounded Corners: Web designers are finally catching-on to a concept that furniture desginers are all too familiar with. Sharp corners hurt! Round-off all corners on your site. It’s OK to leave the occasional odd corner sharp if the other three are rounded. This is stylish and as long as the sharp corner is out of the way, it is unlikely to cause any harm. Superior web sites will combine gradients, rounded corners and soft lines for the ultimate in user comfort while browsing the site.

7) Badges and Chiclets: Badges and chiclets are an important aspect of any Web 2.0 site as they give users choices that they would otherwise not have. For instance, an average user would never know the URL for the official CSS specification. However, the convenient CSS chiclet on your site will put this spec one click away. Your site visitors will be overjoyed. I don’t have to tell you how critically important it is to have one or more RSS feeds on your site. Note that the orange XML chiclet is now uncool. You must use the official RSS logo and for best results, include chiclets from 5–10 other sites for the huge numbers of people that are specific about the feeds they subscribe to such as RSS 0.91, RSS 0.92, Atom, PomDiddly 1.0 etc.

8) _____ this: Include as many action links as possible within your content. It is terribly inconvenient to copy and paste URLs and it significantly raises the bar for site visitors to share content if you do not provide action links such as “Blog This,” “Email This” or “Digg This.”

9) Tabs: Find a way to incorporate tabbed-navigation on your site. It goes without saying, but I will say it anyway — make sure the tabs are rounded, have a gradient and use soft lines. It is also helpful to include numbers in tabs. It’s OK if the visitor has no way of knowing what the number represents. Just seeing the number there hints at the plethora of content that awaits them if they should choose to click the tab.

10) Reflections: Adding reflection to one or more images and text on the page will instantly add a lustre to your site pages that your content never can. Another advantage is that you do not need to update content for many months and your site will still continue to look fresh. Remember to add a “beta” kicker to your primary site logo.

11) License: Having put in all the effort in creating a fantastic Web 2.0 site, the last thing you would want to do is confuse site visitors who want to borrow a background image or graphic from your site. Eliminate the guesswork and include an ultra-cool “Creative Commons License” chiclet on your site. Even if no one borrows the graphics, at least they get a sense of your fairness and willingness to share.

(If it isn’t clear, this is a total tongue-in-cheek post.)