New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.

Learning Razor 1 - RSS-App Part 4: Supporting DNN Search

In this post which is part 4 of my mini-series Learning Razor with an RSS-App we'll enable DNN-Search support for the new Lucene-based search built into DNN in Version 7.2.

What we'll Do and Add In Part 4

  1. Learn a tiny bit about the DNN Search
  2. Learn a bit about preparing data before the view gets to show it
  3. …and why you can't really do this in Razor
  4. …and how we will do it even though we can't
  5. Because the code will get a bit long, we'll move most of it to another file
  6. And then benefit from a much simpler data-binding syntax (the default dynamic objects instead of xml-notations)

The search topic is very complex and I'll write more about it some other day - so let's just focus on some minimal parts for now.

Preparation: Install Everything

Again, install 2sxc and everything just like in Post #2, but in this case:

  • Make sure you're using at least the version 6.3.3 of 2sxc because it fixes a search-bug
  • Also install the V4-App for this lesson from Codeplex or the forge.

If you need help, just watch the video of post #2 in this series.

How does the DNN-Search work?

There are basically two ways to create a web-search.

  1. One is the spider-approach used by Google, which will index all the pages visible to the outside world and use this index when people look for something. This has many benefits and drawbacks. It's super simple and it works in many cases - but then again it will have a lot of problems with security (can't spider protected content), with security again (can't decide what to show when people search) and with data that doesn't appear as text in the output (like JSON-Feeds…)
  2. The other is a more data-oriented approach, where the indexer looks at the data (directly in the DB or through the object-model) and says "give me everything and tell me how to use it". This is harder to implement, more error prone (these are the drawbacks) but more precise and controllable. It also allows us to index things that "don't exist" or add metadata which is never displayed but important for search.

DNN actually has both of these systems built in, but only in the pro version Evoq Content. The DNN-Platform only has a data-oriented, non-spider search. So if we want to create something useful, we must support that search interface.

Why this can't work in Razor…

Razor is a View-Engine. So any code we write will be executed when the module is supposed to be viewed. When the search-index is running, it won't execute view code but will actually execute this command in a module:

I hope to write more about the search, but let me point out for now that a few things look wrong to me in the current implementation:

  1. To support search, you don't support an interface, you must inherit a class ModuleSearchBase. This is bad, but it's the way it is. IMHO it should be a ISearchable or something (similar to the previous version). I don't know why they went from an interface-design to a class design.
  2. The signature of the the GetModified... command also uses "real" classes instead of Interfaces. IMHO it should be a IList<ISearchDocument> instead of IList<SearchDocument>. Yes, the "I" does make a big difference...

So: I believe these interfaces will change again in a near future - for now, they work.

…but we can make it work

 In a perfect MVC-situation, there must be a controller that delivers data for the search, while the view should have no role in this at all.

So in reality, when you create a module in DNN, you will have to support these search commands. If you want to give the end-designer (the web-designer or view programmer) the power to modify this, you must do something in addition to the View engine.

Now 2sxc has a powerful data management system handling versions, languages and search. If we could add the RSS-data to the modules data-pipeline, it would be indexed automatically

So here's what we did

  1. The Razor-Views in 2sxc always have a Data object containing streams of .... data (surprise!). 2sxc prepares this data before it starts up the View - and the data contains things like the Content (stuff the editor added in this module, this is in the default-stream), but it can also contain other things…
  2. The Razor-view might need to add data which is not accessible in 2sxc - like this RSS-feed. But there are also other possibilities, like SQL-queries or even 2sxc-data with special filters applied. Because of this, there is a CustomizeData method that is always called if it exists in the template.
  3. This CustomizeData is used to prepare data for the view
  4. …and it also called when the Search-Crawler indexes the module. So in this method you have the ability to add data to the Data-Object - which would then end up in the search index.
  5. Note: the code got a bit long (about 60 lines of code) - so we outsourced it.

This is the code for the preparation work:

Note that there is more to it - like there are status variables so that your code knows you're in index-mode, and there is another command CustomizeSearch for advanced search customization like alternate URLs (see documentation). But for now, let's keep it simple.

The Search Integration way 2sxc does it

This is how our Views can customize the search. Note that there are other ways - but if your module ever supports custom Razor-Views, you might want to plan with something like this as well. 

Here's the inline code (calling up the external functions and attaching it to the pipeline:

This code does the following

  1. Internal code: open the external library, call the helper function
  2. External code: Retrieve the data as always
  3. External code: Convert it to 2sxc entities by
    1. creating a data-table
    2. putting the feed in it (with thumbnail and everything)
    3. and then using the data table as a DataSource.
      This has to do with the Data-Pipeline concept of 2sxc, allowing you to chain data-functionality. So once something is in a DataSource, it can benefit from other data-sources (like URL-Filters, advanced caching, etc.).
  4. Internal code: Then it attaches this new data-source to the main Data, and that's it!

And search works automatically!

Since 2sxc automatically adds everything in the Data["..."] object to the search results, it all works now - see this example:

The Template Code can now be Simplified

Remember that the placeholders in the HTML were long and ugly? Since the RSS-feed is now a standardized entity, we can loop through the Data-stream instead of the XML-object.So instead of this

We now get the nicer code like this:

See the Code and Live Result But it's even better to just download the App and work with it.

Now Try a bit yourself…

Go ahead and mess about with the code. You can do it in Visual Studio or with the edit-template functionality. And don't worry: you can always uninstall the App and install it again when you mess it up :).

Wrapping up Phase 4 - Good and Bad

So now we have a much improved Razor-based App. A lot of the last shortcomings are fixed:

  1. DNN-Search Support now works
  2. ...but doesn't cache - so the RSS-feed will be requested every single minute because the search asks for it
  3. Template looks much simpler, because the placeholders got nicer
  4. Long data preparation-code is outsourced (and can be shared across templates)

…but it still has many shortcomings like the following:

  1. It's not multi-language capable - so if you needed a different feed in another language, again you would have to create a new script - or additional fields for each language
  2. The data is not cached - so the RSS-feed will be requested
    1. every single minute because the search asks for it
    2. and for every page view
  3. The admin can't control the presentation (like decide to show/hide images or reduce the amount of items)
  4. The admin couldn't easily switch to another view like a 2-column look instead of a table

All these shortcomings will be handled in the following lessons :). Stay tuned!

With love from Switzerland


Daniel Mettler grew up in the jungles of Indonesia and is founder and CEO of 2sic internet solutions in Switzerland and Liechtenstein, an 20-head web specialist with over 600 DNN projects since 1999. He is also chief architect of 2sxc (2SexyContent - see forge), an open source module for creating attractive content and DNN Apps.


There are currently no comments, be the first to post one.

Comment Form

Only registered users may post comments.


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Davies (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out