Mcbeev.com

Taking it one line of code at a time

Today I'm writing a small quick tip type of post that allows you to customize the Smart search wep parts inside of Kentico CMS in a way that I think helps the usability of searching Kentico based web sites.

Kentico's Smart search web parts easily create functionality that allow you to have a very powerful search engine right at your own disposal. The built-in functionality indexes your site's content and displays search results that are ranked based on relevancy. Trust me, it's much more than just a SQL WHERE clause.  I'm not trying to cover the entire spectrum of search inside a Kentico site so if you are not used to using the Smart search check out the Smart Search documentation on Kentico's Devnet.

 

Kentico CMS Smart Search Web Part

 

When you add a Smart search dialog with results web part and configure it to search your site, you may notice that if you don't type anything into the input box and click the search button, generally there are no results returned. Now when I first ran into this I thought it was because I did something wrong while setting one of the web part's properties, however a quick double check showed that I had it setup correctly. 

I worked on a bit more and ended up not having any luck, so after a quick email to the great Kentico support team, I was quickly informed of a not so widely know web.config tweak. The support team reccomended that I add the following key to my application settings node in the main web.config file of my installatton.

 

<appSettings>
          <add key="CMSSearchOnlyWhenContentPresent" value="false" />
</appSettings>

 

When this key is present in the web.config file, the Smart search will perform the search operation without any text present in the input box. This also helps out if you are using Smart search Filters to filter your search results. 

So there you have it, by adding this key into your application settings you can no search without forcing the user to enter at least a few characters.


Reader Tip - Cick the Hide Sidebars link at the top right toolbar on this page to give you some more room to read this post on the screen, because it is code heavy.

The Kentico CMS WebService is a little known tool when it comes to the functionality of Kentico. It is used in a few Web Parts, the Repeater for web service Web Part comes to mind right away.

The WebService’s job is pretty straightforward, it’s main purpose,  as you could probably guess, is to return data from the Kentico database via a SOAP call.

In this post I will show you how to enhance the built in functionality to also allow you to directly call the Kentico WebService from a JavaScript method. This is useful if you want to have some rich interaction on the client side of your pages such as creating a dynamic menu on the fly, or creating a rotating image banner.

To start out, notice that there is an empty WebService sitting around in your project already. It is located at:

~/CMSPages/WebService.asmx

Now if you aren't familiar with an ASP.NET WebService notice that this looks like an empty page. That is OK. There only needs to be one declarative that states the class name and where the code for the class exists. The code behind file for the existing WebService is located at:

~/App_Code/CMSPages/WebService.cs

Opening that up shows us a pretty basic example of a WebService.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
    /// 
    /// Constructor.
    /// 
    public WebService()    {    }


    /// 
    /// Returns the data from DB
    /// 
    /// String parameter for sql command
    [WebMethod]
    public DataSet GetDataSet(string parameter)
    {
        // INSERT YOUR WEB SERVICE CODE AND RETURN THE RESULTING DATASET

        return null;
    }
}

Now lets make some changes to this WebService code that allows you to call it as a ScriptService. And don’t worry, all of the changes that we make won’t break any of the ways this service is used already in the system, we are only adding functionality.

What’s a ScriptService you may ask ? Well a ScriptService could be defined as a special kind of WebService that knows to serialize each web method’s results as JSON.

using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Script.Services; // ADDED

/// 
/// WebService template
/// 
[ScriptService]	// ADDED
[WebService(Namespace = "http://webservices.mcbeev.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
    /// 
    /// Constructor.
    /// 
    public WebService()    {    }


    /// 
    /// Returns the data from DB
    /// 
    /// String parameter for sql command
    [WebMethod]
    [ScriptMethod] // ADDED
    public DataSet GetDataSet(string parameter)
    {
        DataSet ds = null;

	//Code to query the CMS Tree and Return Items


        return ds;
    }
}

You can test out your changes to see if it worked by building the web site and running it. After the start page opens up navigate to:

~/CMSPages/WebService.asmx/js

// if Debugging is enabled on web.config you can also hit

~/CMSPages/WebService.asmx/jsdebug

You should get a response that includes some dynamically generated Javascript that looks like this: (the jsdebug version is not minimized and includes more info, as well as your comments)

var WebService=function() {
WebService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
..... abbreviated ...
WebService.GetDataSet= function(parameter,onSuccess,onFailed,userContext) {WebService._staticInstance.GetDataSet(parameter,onSuccess,onFailed,userContext); }
var gtc = Sys.Net.WebServiceProxy._generateTypedConstructor;
Type.registerNamespace('System.Data');
if (typeof(System.Data.DataSet) === 'undefined') {
System.Data.DataSet=gtc("System.Data.DataSet");
System.Data.DataSet.registerClass('System.Data.DataSet');
}

This result we are now seeing is a generated JavaScript proxy class. It takes care of the heavy loading and serialization of methods, responses, and complex types so that the client side knows how to handle using each of these responses and/or complex types. The key is at the bottom, the WebMethod we made above is now callable via WebService.GetDataSet(…) as long as we have this reference on our page somewhere.

<script type="text/javascript" src="/CMSPages/Webservice.asmx/js"></script>

Note that if your ASPX Page Template or Portal Page Template has a ScriptManager control on it, you wouldn't have to manually add in the script src tag. You could add a reference to the WebService in the ServiceReference collection property of the ScriptManager. Next, we need to write the followign JavaScript somewhere on our page:

function testService(){
	WebService.GetDataSet("", serviceSuccess, serviceFailed);
}

function serviceSuccess(results){
	if(results)
	{
		alert("worked");
	}
}

function serviceFailed(error){

     alert("Stack Trace: " + error.get_stackTrace() + "/r/n" +
          "Error: " + error.get_message() + "/r/n" +
          "Status Code: " + error.get_statusCode());
}

The testService method above would hit our new ScriptService asynchronously, and it should either return a result that alerts us that the call worked, or that it failed and why. There is a ton more you can do with ASP.NET AJAX WebServices but I don’t want to get off on a tangent on that. Just click through that link and read up more on it if you are interested or need more guidance.

Now lets put together a final example that grabs some data from the Kentico system and returns it to the client side JavaScript.

Modify the WebService.cs class to add in this WebMethod as follows:

    /// 
    /// Returns node names from the CMS Document Tree based on the path parameter
    /// 
    /// Path to search the Tree, such as /%
    /// List of TreeNodes
    [WebMethod]
    [ScriptMethod]
    public List GetTreeNodeNames(string PathParameter)
    {
        if (string.IsNullOrEmpty(PathParameter))
            throw new ArgumentException("No PathParameter specified");
        
        int cacheMins = 30;
        bool condition = true;
        string cacheKeyName = "GetTreeNodeNames";
        DataSet ds = null;
        List treeNodes = new List();

        using (CachedSection cs = new CachedSection(ref ds, cacheMins, condition, null, cacheKeyName, PathParameter))
        {
            if (cs.LoadData)
            {
                // Get from database
                ds = TreeHelper.SelectNodes(PathParameter, false, "CMS.MenuItem");

                //cs.CacheDependency = ...
                cs.Data = ds;
            }
        }

        if (ds != null)
        {
            if (ds.Tables.Count > 0)
            {
                foreach(DataRow dr in ds.Tables[0].Rows)
                    treeNodes.Add(dr["NodeName"].ToString());
            }
        }

        return treeNodes;
    }

A few things to notice here. I'm using Martin Hejtmanek's new caching method to get my DataSet of information. There is really no reason to make a direct SQL call every time, so let's leverage the really awesome capabilities of the Kentico caching mechanism. This method exists in Kentico CMS 5.5+ only. Make sure you update your site before trying this.

Secondly, I’m not using the input parameter to specify some information so our new script, i.e the NodePath, we will have to pass that along as well in the JavaScript.

Thirdly, automatic serialization of complex types is great, like a DataSet, but the whole DataSet object that Kentico’s API returns is fairly heavy. Don’t try to return the whole thing in real world examples. Remember we are trying to keep this thing lightweight and fast. As you can see above I extract out the property I am looking to use and return in a more simple List of string. You can make your own DTO object here if you would like. A simple DTO should serialize just fine.

Updated JavaScript example:

function testService(){
	WebService.GetTreeNodeNames("/Examples/%", serviceSuccess, serviceFailed);
}

function serviceSuccess(results){
	if(results)
	{
		var nodes = results;

		for (var i = 0; i < nodes.length; i++) {
			alert(nodes[i]);
		}
	}
}

function serviceFailed(error){

     alert("Stack Trace: " + error.get_stackTrace() + "/r/n" +
          "Error: " + error.get_message() + "/r/n" +
          "Status Code: " + error.get_statusCode());
}

And there you have it. Your test page should now be alerting some page names.


This post applies to using Kentico CMS 5.5+ and Visual Studio 2010. It may seem a bit basic to some veteran Kentico developers, but I had to show a few co-workers the ins and outs of setting up a solution the right way. Once they had it, they were able to debug through a local project that contained both the core Kentico code and the extra sample code for creating a custom event handler.

You might have a question on what exactly a CustomEventHandler is for Kentico. Well it is basically an avenue that once you have it setup you can extend and customize Kentico to do things that it can’t do out of the box. There are a multitude of events that your code can subscribe to and give you the ability to do whatever you want on almost any action in the CMSDesk and beyond.

The first part of the process involves installing the base product from Kentico. If you don't have it already, go ahead and grab the download of the Web Installer from Kentico's site. Once you get it downloaded double click on KenticoCMS_5_5.exe. Click Next at the welcome screen and accept the licensing terms, and then you should be asked for a location to extract the download to. I generally leave the default path alone, for the most part it makes sense to put it in Program Files. Click Next after you have chosen your path and it will extract to that location. After that is done we get to the interesting part. You should now be at a screen like:

_web_installer_1 

There are a couple options for how to install the Kentico Product, but for the purposes of this post we are talking about using the ASP.Net Framework version 4.0 and Visual Studio 2010. Choose the first option and click Next.

Next we are asked the location of where we would like the code for Kentico CMS to be installed. For our purposes we want to choose the second option, I want to use the built-in web server in Visual Studio 2010.

_web_installer_3

The next option is where we would like to place the code that we will be running locally.

 _web_installer_4

After that we are presented with a choice of Full Installation or Custom. Go ahead and pick the Full option, it includes everything, especially the Custom Event Handler starter code that we need.

_web_installer_5

After clicking next the installation will really kick in and copy all the files you need. Go grab a cup of coffee because this step takes some time. There are a lot of files to copy.

_web_installer_6

 If it all works out, and it should you should finish up at a screen that says complete and has a link to your new solution.

_web_installer_7

Click that link to open up your solution in Visual Studio 2010. The solution that the web installer created should open up and it should be fairly easy to see that there is one web site already part of the project that contains all the code required to run a Kentico CMS site. Pressing F5 will start the web site up via the built in Visual Studio 2010 web server and start you on your way to debugging.

Now the first time you run the code you will be asked to setup the database for a new installation of Kentico. That is sort of outside the scope of this post, and Kentico has a great support document already created that you can check out for help with if you need it. But at this point we have successfully installed the core product locally and can debug it.

Now that we have the base solution and website ready lets get into the real reason we are here though. And that reason is how do we add on the Custom Event Handler starter code so that we can customize various events inside the Kentico system.

Head back on over to the location of which you installed Kentico to on you drive. If you notice in the root Kentico folder there is a sub folder called CodeSamples. Inside that folder is where our target code lies.

location_folder

Since I’m a C# guy I will be choosing the project CustomEventHandler in here. That folder contains a class library project that has some starter code for us. Now back to the Visual Studio environment. Go ahead and right click on the Solution named Kentico5-5 in the Solution Explorer and add in an Existing Project. When the browse window comes up choose the CustomEventHandler.csproj file in your CodeSamples/CustomEventHandler folder that we just mentioned.

Kentico5-5 Microsoft Visual Studio add existing project

Now at this point the tricky part comes in with the fact that the Sample Code is a bit old. Hint, hint Kentico devs!  Visual Studio will want to convert the project to a .NET Framework version 4.0 project and set the target framework property for you via the Conversion Wizard. Just click Finish and ignore the conversion log.

At this point you are probably saying great, why do I now have like 14 warnings and the thing doesn't look like it will build. That’s because the the reference names are wrong for the sample code.

Kentico5-5 Microsoft Visual Studio references

Just go ahead and right click remove the broken references below

  • CMSHelper
  • DataEngine
  • GlobalEventHelper
  • GlobalHelper
  • SettingsProvider
  • SiteProvider
  • TreeEngine

And after that add back in the correct ones from the list below. The files can commonly be found in your new bin directory normally located at C:\InetPub\wwwroot\KenticoCMS-5-5\Bin\

  • CMS.CMSHelper.dll
  • CMS.DataEngine.dll
  • CMS.GlobalEventHelper.dll
  • CMS.GlobalHelper.dll
  • CMS.SettingsProvider.dll
  • CMS.SiteProvider.dll
  • CMS.TreeEngine.dll

As you add back in references you will probably get a strange error talking about .NET Framework versions. Answer Yes to that. It will convert the reference to correctly use version 4.0.

Kentico5-5 Microsoft Visual Studio add CMSHelper

After you fix up all the references your complete solution should build.

Next, to be able to debug into the Custom Event Handler code, you will need to add a reference from the output of the class library project to the Kentico website in the solution. So on the bin directory right click it and choose Add a Reference. Then select the Projects tab and choose the only one in there, CustomEventHandler. This will tie the two projects together.

I should mention here that at this point if anything went wrong, like the project still isn't building go ahead and double check the target framework of the class library project (Right-Click Properties on the project) and make sure the Target Framework is set to .NET Framework 4 like below.

 Kentico5-5 Microsoft Visual Studio Target Version

Next we need to let the instance of Kentico know that we are using CustomEventHandlers. To do so we need to add an application setting in the root web.config like so:

<appsettings>
	<add value="C#" key="CMSProgrammingLanguage" />
	<add value="http://localhost/WebService/webservice.asmx" key="WS.webservice" />
	<add value="CU05-20100804-YfqLrL" key="CMSTrialKey" />
	<add value="true" key="CMSUseCustomHandlers" />
</appsettings>

As Kentico states in the documentation for this key you may change the name of this key also. Check out the docs here for how to do that.

Save and close your web.config and you should be all set with that. There is one last step we need to do, and that is set a break point on some code. One of the most common methods to use in the CustomEventHandler is the OnAfterUpdate method in the CustomTreeNodeHandler class. Add in the two lines below to have something to test with into the method. Set your breakpoint on the second line.

/// Summary
/// Fires after updating tree node in the tree. Performs the additional actions after the tree node is updated.
/// 
/// TreeNode object to update in tree
/// TreeProvider object to use
public override void OnAfterUpdate(object treeNodeObj, object tree)
{
     // INSERT YOUR CUSTOM AFTER-UPDATE CODE
    TreeNode node = (TreeNode)treeNodeObj;
    string nodeName = node.NodeName;
}

Set the web site as the Startup Project and then go ahead and hit F5 to run the solution. Since this is the second time you have run the site you should not be prompted to setup a database again. You should go to the default page of the site you first created. Login to the CMSDesk and then edit a page in the Document Tree. As soon as you click the Save button the OnAfterUpdate event should fire on your updating TreeNode and  debugger should pick it up.

Kentico5-5 Microsoft Visual Studio Debugging

I hope this tip helps you out. I think my co-worker owes me a beer for writing this all out for him.


9 Reasons Why Your Company Needs a Wiki

I’m a huge fan of using a wiki to help organize our business and it’s various functions, such as creating software. In fact I usually end of recommending the use of a wiki to almost all my clients who do not already have one.

If you are not familiar with what a wiki is, let me give a simple definition right here:

A wiki can be defined as a web page or web site that allows a community of users to add, edit, and maintain content that usually surrounds a given topic or topics.

It’s a simple concept really, a web page that holds content, that’s almost no different than any web page out there. But the real difference between any old web page and a wiki is that anyone can edit a wiki right on the fly, while a web page is normally maintained by one person. In fact the more users that a wiki has adding and editing content, the more relevant and informational that wiki will become.

Now that we know what a wiki is let me get on to why I think your company could be better off than than it is today if they implemented a wiki.

1. Knowledge is power

Collecting all the pieces of of knowledge from a persons head is a tough thing to do, no matter what the topic or project is. The old saying goes there is no substitute for experience and I firmly believe that. However, having a place that becomes the fountain of knowledge for you organization is very powerful.

The wiki becomes a repository of knowledge that all employees can contribute to and learn from. The more knowledgeable your employees are, the better they can serve your customers, the better they can perform their jobs, and hopefully that leads to making the company more profitable.

2. Documentation can save your life in a pinch

One of the most common uses of having a wiki is to have a single point to document a company, client, or project. The benefit of having a wiki page on a topic, such as a project, is that it is easy to add and maintain small pieces of documentation that sometimes don’t fit well into a full blown spec or project plan. Or sometimes just having a link that gets you to right location of the project plan or latest revision of a quote can be just as important.

Tools of the Trade - by buffcorephil

A real world example of how having the wiki as a source of documentation for a project can save you goes something like this. Your company completed a project for a client 6 months or so ago. The team member that actually worked on the project got promoted to another job role at another location, or worse yet left the company. Hopefully before that happened that team member wrote down everything you would ever need to get to the source code, login to the production server, or figure out who set the requirements on the client side in the first place. That wiki page may save your butt when the client calls and asks why his web page is displaying an 500 Internal Server error.

3. Searching for information is tedious

How many times have you played out this scenario. A customer asks you about a detail of how business process X works. Let’s say X is the process of buying a product from an online ecommerce site that you maintain.

What’s the first thing you normally do ? Maybe click the help link on the shopping cart page? Maybe you start searching your project folder to find the right solution or project file for Visual Studio to open up and look through some comments for the GetProduct method? Or god forbid, you might open up windows explorer and press F3 to search your network file system looking for a word document or text file that contains the ecommerce API and/or API guide?

searching

If you are like me then you have hundreds of files and/or folders that Windows has to search through and it takes forever, while most of the time not producing the search results you need. And most of the time if you do end up finding the right place the answers within the document don’t help out all that much. This I think is the definition of a tedious process.

One of the most important aspects of a wiki, is that all the content is searchable. Usually if the wiki is a good one, it will have a built in search engine behind the scenes that indexes every word and phrase on every page. That way when you perform a search it is usually as fast as popping open Google and typing in your topic. The search results are normally weighted to get you to the most important wiki page on that search query. Wikis make searching easy.

4. Crowdsourcing is for real

Wikipedia defines crowdsourcing as the act of outsourcing tasks to a large group of people through an open call. With the technologies that the web has brought us over the last few years this has never been truer or easier to do than right now. This principle holds true in any company no matter what it’s size is.

Crowds by Mike PD

Years ago it used to be that there was project manager, technical writer, or gasp, even a developer that was in charge of being the primary documentation creator. And let’s face it, most technical people are not great at writing documentation. Here is where crowdsourcing can really transform the way that knowledge is tracked with a tool such as a wiki. 

As users come onboard to your company they can read and add to any wiki page they want. As each person contributes the document grows and lives with them, and the information just gets better and better. And guess what you don’t have to have a dedicated technical writer to keep that document up to date, you crowdsourced it.

5. Easier to maintain than Office documents

Don’t mistake me, this is not a comparison of Microsoft Office Word to Open Office Writer. I’m not about to go there. What I am referring to is that the type of documents that need a specific program to edit them or share them, does not help you get your job done faster or better. A wiki is a web app that is available to the whole internet or even only your company’s internal network. No special tool is needed other than a browser and a network connection to get to that data, read it, and make a business decision from that knowledge.

It is flat out easier and faster to add or change a piece of information on a topic as your project of client relationship changes via a wiki. This makes it easier to keep all of your business’s information up to date and accurate.

6. Linking related information is crucial

Another important aspects of wikis are how you get from one wiki page to another. This is done using a linking system. Most wikis allow a user to create a link to another wiki page, or even external web page by placing a square bracket around the phrase that they want to link. The following example illustrates this:

To create a link that looks like this:

BizStream will be architecting this project

You would write in the wiki editor this:

[BizStream] will be architecting this project

A link, or a way to jump around from wiki page to wiki page, is as important to a reader or employee as jumping around from link to link on a Google search result page is. Wikis provide an easy way to do this.

A real world example of this is that at BizStream we keep a wiki page on each company that we deal with, and on that company’s wiki page we always include a project section that contains links to all the project wiki pages that we do for that company. It is really nice to be able to navigate quickly from the top level company page to each of it’s projects and see who is leading them, or who is the main customer contact for that project.

It ends up looking like

Company: BizStream

Open Projects

  • BZS-2010-01: Kentico CMS Website Implementation
  • BZS-2010-02: Custom Sharepoint Web Part Integration
  • BZS-2010-03: Database Maintenance Plan Review

7. Built-In document revision and revision control

The commenting and revision system in most word processing tools is overly complicated in my opinion. I have seen enough red lines and red arrows to last for the rest of my lifetime. Also what about when the user forgets to turn tracking changes on, or overwrites the file in the folder. This can become an administrative nightmare.

Normally wikis contain a simple and built-in method of storing all the different revisions of a wiki page. Most good wikis also give you a tool to see the differences between each revision all on a single web page, i.e what was added and removed. Wiki Administrators usually have the power to rollback to a certain revision if something was lost, or if an anonymous user is being malicious and tries to hijack some content. Wikipedia is famous for it’s moderator groups and level of standards they hold to a page and it’s content.

8. Categories / Tags easily organize your content

The popularity of tagging a photo, page, or email has become increasingly useful and popular in almost all things these days. Take FaceBook for example they let you tag almost anything. You can tag each person in a photo, and that tag becomes a link right in that photo, and anyone can click on that person right there and be taken to their profile. It’s just an easy way to organize links or content really.

The reason that tags become useful is that you can narrow down your search results or subscription topics to just what you care about. Even this blog for another example. I have a lot of personal blog posts here, but if you don’t really want to know about them you can just subscribe to the the technical categories or tags and see what you want.

tag 

One tip here though. Don't get too hung up on organizing the content into a very structured layout. This isn't a file system it's meant to be a free flowing system. Just start creating your pages and adding links as you go. The content of the page is way more important than having it look right.

9. The cost is nothing for all the benefits you get

Business is all about using your resources wisely. And what’s wiser than using something that is free. There are many free open source wiki’s you can use. My favorite is ScrewTurn Wiki.

I actually have a lot of reasons why I like and use ScrewTurn as my wiki of choice. But this post has already grown to be a bit bigger than I originally thought so I will explain why next time. So there you have it. My 9 reasons why I think your company needs a wiki.

Please leave any feedback or questions you have in the comments.


I’ve been pretty surprised at the traffic, mention, and email feedback that my last post, 7 Things you might want to check after launching a new Kentico CMS website, has received. In fact I was presented with a very good question in my inbox today about a detail from the fourth item in that list.

Pretty much the question boiled down to, why after submitting the Google site map URL to Google’s Webmaster tools, was the specified website’s pages not showing up in the resulting index or when viewed at the sites ~/CMSPages/GoogleSiteMap.aspx page.

Since the question came in from a friend, I decided to dig deeper and lend a hand. As soon as I logged into the site’s CMSDesk I quickly noticed what was up. Most of the content pages were using Custom Document Types. I was actually impressed to see this because it is sort of an advanced feature to use inside Kentico and normally an under utilized feature as well.

The output of the GoogleSiteMap.aspx page looked something like this, only the normal Menu Items from the CMS Tree:

 

Kentico CMS Google Site Map default

 

So after some quick research I found the devnet article on how to integrate the Googe site map feature. After reading the second paragraph of that article I knew exactly what was up. Turns out that by default the Google site map feature from Kentico only includes the “Page (menu) item” Document Types. This makes sense for someone that doesn’t have a lot of custom Document Types or dynamic content.

However, if you use custom Document Types, and you should, they rock, then you need to pop open your favorite text editor and add a very small amount of code to make the custom pages show up. Open up ~/CMSPages/GoogleSiteMap.aspx. The server tag in question that we are looking to change is the <cms:GoogleSiteMap> tag.

Default:

 

<cms:GoogleSitemap runat="server" ID="googleSitemap" TransformationName="CMS.Root.GoogleSiteMap" CacheMinutes="0" OrderBy="NodeLevel, NodeOrder, NodeName" /> 

 

Now what we need to do is add in whatever custom Document Types that we have, into a ClassNames property, chances are it is not there already. Let's use BizStream.TeamLeaderProfile in this example.

Change To:

 

<cms:GoogleSitemap run at="server" ID="googleSitemap" TransformationName="CMS.Root.GoogleSiteMap" CacheMinutes="30" OrderBy="NodeLevel, NodeOrder, NodeName" MaxRelativeLevel="-1" ClassNames="CMS.MenuItem;BizStream.TeamLeaderProfile" />

 

Don't forget that the property can accept multiple custom Document Types delimited by a semi-colon. Now save the page and you are all set. All of your pages should show up at the GoogleSiteMap.aspx url. Go ahead and browse to it to check it out.

You should now see the extra URLs part of the page output like:

 

Kentico CMS Google Site Map with Custom Document Type

 

I’d also like to point out that the default control does not look to be using the Cache system provided Kentico, CacheMinutes=0. I would recommend upping this value from 0 to at least 30 minutes if not more. There is a small chance that 0 could mean inherit from the top level tree or site, but I haven’t been able to verify this or not.

Note: if your curious about what kinds of pages that a custom Document Type can generate, check out the About page over at BizStream.com. That’s one example of how BizStream uses custom Document Types.

One last tip, like the devnet article mentions you don’t have to use that path to submit to Webmaster tools with, it is kind of long. You can change it to whatever you want by going to CMSSiteManager -> Settings -> (global) in list -> URLs -> Google sitemap URL.

I hope you enjoyed this small article about using the Google site map feature of Kentico CMS. As always leave feedback and opinions in the comments or send them to me email.


(Note: this post assumes that you read the primer post on URL Rewriting & Aliasing in Kentico CMS)

 

In my last post I described what it takes to use the URL Rewriting and Document Aliasing capabilities of Kentico. I also promised a twist to those who made it through the entire blog post, and here it is. So without further ado, I now present my solution for creating a Custom Document Alias in Kentico that is QueryString aware.

Let’s get started. Now that you understand more about URL Rewriting say you had a URL like this:

 

http://mcbeev.com/products/item.aspx?type=Chips&name=Baked Lays

 

Pretend for a minute that your store also sold candy bars, and we decided to reuse the same old page to display both types of products. We would still have a URL like:

 

http://mcbeev.com/products/item.aspx?type=Candy Bars&name=Snickers

 

Our example translated into a standard Kentico setup:

 

url_tree_2

 

And here ladies and gentlemen we hit our first snag with the Kentico CMS out of the box and aliasing. You can URL Rewrite and even Document Alias any node in the content tree. However, the one small gotcha is that you can not create an Alias that looks at QueryString values, or anything after the question mark.

The default Kentico engine will just replace any special character with a dash in the in the URL Path or URL extension field of the Document Alias, therefore wiping out the important part of the QueryString that our example URL above is relying on.

I have actually run into this in my real world projects where I am upgrading a pre existing site that has lots of old links from it’s website as well as other websites that match the URL format in our above example.

Bummer.

To fix this we have to get a little creative and write some code. This is a two part solution. First, we need to make a generic redirector page with a Document Alias of the first part of the URL above.

I created a new page called RedirectItems at the root of my Kentico site and then added a Document Alias like so:

 

item_Redir

 

The purpose of this page will be catch all the incoming requests regardless of QueryString value, and hand it off to the right place after running a bit of code on that page, or Web part.

The next step we need to do is create a new custom Web part. The purpose of this new Web part will be to to grab the information out of the the request that we need. To do so I used these instructions from Kentico on how to create a new custom Web part.

 

WebPart_Redir

 

The key here is that we create the new Web part called Redirector (or whatever you like) and then give it one Property called RedirectToPaths. This is where you will set your URL templates for how we can handle the QueryString redirects.

 

WebPart_Redir_Properties

 

At this point you are safe to click save on the Create Web part Screen. Next we need to add in some code to our Web Part.

Once the new Web Part is added in the CMSSiteManager and the file is in ~/CMSWebParts/Your Category Name/ you can open up the source code of Redirector.ascx.cs with your favorite Text Editor or Visual Studio.  And add the following OnPreRender method.

 

protected override void OnPreRender(EventArgs e)
{
	base.OnPreRender(e);

	if (this.StopProcessing)
	{
		// Do nothing
	}
	else
	{
		//Collect the URL information from the current Request
		string currURL = HttpContext.Current.Request.RawUrl;
		string queryString = string.Empty;
		string newURL = string.Empty;

		//Check to make sure some query string variables exist
		int iqs = currURL.IndexOf('?');

		//QueryString variables exist, put them in a string.
		if (iqs >= 0)
		{
			queryString = (iqs < currURL.Length - 1) ? currURL.Substring(iqs + 1) : string.Empty;
		}

		if(queryString.Length > 0)
		{
			//Parse the querystring		
			NameValueCollection qsKeys = HttpUtility.ParseQueryString(queryString);

			//Pull in the Path Expressions from the Web Part property called RedirectToPaths
			string redirectToPaths = (string) this.GetValue("RedirectToPaths");

			//If the property is empty do nothing
			if(redirectToPaths.Length > 0)
			{

				//Split out the property value by a comma in case there are multiple
				foreach(string p in redirectToPaths.Split(','))
				{
					string path = p;
					bool allKeysInPath = true;

					//Iterate through the keys and replace the key with the value
					foreach (string key in qsKeys.AllKeys)
					{

						if(path.Contains("{"+ key + "}"))
						{
							path = path.Replace("{"+ key + "}", qsKeys[key]);	
						}
						else
						{
							allKeysInPath = false;
						}
					}

					//Handle whitespace
					path = path.Replace(" ", "-");

					//Make sure we got a redirectToPath that handles all the keys
					if(allKeysInPath)
					{
						newURL = path;
						break;
					}

				}

				//Check if we generated a new URL
				if(newURL.Length > 0)
				{
					//Redirect to our new path
					Response.Redirect(newURL);
				}

			}

		}
	}
}

 

 

 

That’s all the code we need to touch, so close and save the file. Now let’s add our new Redirector Web Part to our site. Open up the CMSDesk again and go to where you created the page called RedirectItems from above. Click on the Design tab of the page and add in new Redirector Web Part that we just created. Then click configure. You should be at a modal window that looks like this:

 

WebPart_Redir_Filled

 

Notice our RedirectToPath property shows up and I have typed in two URL templates. Go ahead and copy the second string /Products/{type}/{name} into your Web part. Then click OK. I think you can probably guess how that maps to our original problematic URL of:

 

http://mcbeev.com/products/item.aspx?type=chips&name=Baked Lays

 

Basically the code will replace anything inside the curly brackets that matches the name of the parameter with the value of the parameter. So for the preceding example, we will end up being redirected to the correct location of:

 

http://mcbeev.com/Products/Chips/Baked-Lays

 

So there you have it, this custom Web part will now give us a small enhancement to the built in ability of Document Aliasing for Kentico CMS. The code for the Web part can be found at the link below.

I hope this idea helps you maintain working links when upgrading a pre existing site the way it did for me. As always please feel free to leave feedback for me in the comments.

 

Web part code download


Kentico CMS is extremely powerful when it comes to controlling the URL of a website. Right out of the box, you get the power of aliasing whatever URL you want to whatever document or resource you have in the content tree.

Heck since Kentico 4.x you can even mask/change the extension or just get rid of it all together, to get more control of your site’s URLs.

I can’t stress enough how beneficial this feature is when it comes to creating SEO friendly links, maintaining out of date website paths/structure, or just making it easier on your visitors to reach the pages that they need to get to.

Let’s get started with an example. For instance let’s say your website had a products section that sold different types of potato chips. My favorite potato chips are Baked Lays. So we will go with that for the example.

Way back when developers didn’t do much to make the URL SEO or user friendly, you would have a typical URL like these:


http://mcbeev.com/products/chips.aspx?name=Baked Lays

Google and other search engines see this only as one URL, …/chips.aspx, which doesn’t do us very good.

Now let’s say you had this same website in Kentico. It might look something like this:

 

url_tree

 

There a few things to notice, first if you navigate to the Baked Lays page your URL would be:


http://mcbeev.com/Products/Baked-Lays.aspx

This is nice right? No crazy question mark in the QueryString or namevalue pairs. This is one example of URL Rewriting. Behind the scenes there is no physical file on the file system that IIS is serving out. The Kentico 404 HTTPHandler is intercepting the request and and feeding it through the content in the database of the site you have, and serving out the correct page based on that.

The second thing to notice is the .aspx extension. I mentioned above that you can mask that extension or even get rid of it. We see it here because by default in Kentico Extensionless URLs are turned off. If you check the Friendly URL extension field in the CMSSiteManager –> Settings –> URLs and SEO section, you will see .aspx value. Just clear this field out and click save and now URLs will work as:


http://mcbeev.com/Products/Baked-Lays

As you can see your end result is even nicer now.

(Note: You may need to configure II6 or II7 to handle Extensionless URLs as well, please check out the Kentico Documentation for further info on that)

So for instance, if you also sold Doritos, your more savvy users might be able to just look at the URL in the address bar and guess what they should type in to get to a different product page. Maybe:


http://mcbeev.com/Products/Doritos

And it would just work. This really just brings a nice and logical experience to your users, and Kentico does a great job of it.

One more point on Document Aliasing. An alias allows you to make up a URL that can be completely different than what the name of the document is in the Tree. To add an Alias go to the CMSDesk –> Select your Page –> Properties –> URLs subtab:

 

alias

 

You can see that I added a Document Alias with a URL Path of /Products/Best-Chips-in-the-World. If you copy that into your browser that will lead you to the exact same page as /Products/Baked-Lays. You can have as many of these Document Aliases as you want on each document.

Now I know what you are thinking if you are a long time user of Kentico, and that probably is: Brian why are you writing a blog post on such old features like this ?

And the sixty four thousand dollar answer is… I want to make sure that you have a good understanding of URL Rewriting and Document Aliasing, because in my next post I am going to throw a twist into the the whole situation and solve one shortcoming that Kentico has on this very topic.

Check back next time!

Update: See the next post in the series here.


Don't forget the simple things when it comes to Kentico website launches

Kentico_2D_CMS_width200px

You have just finished importing your export file onto the live server, generated that fresh new license file and installed it, double checked your server's host headers, and fired up your browser of choice to http://www.somesite.com. Now wipe that smile away from your face, you still have work to do.

 

1. Minimize any JavaScript files that you can.

Strip out those white spaces people, it will make your site appear faster to load and execute to your users. If you don’t have a tool that you already use, or don’t know exactly what I’m talking about check out JSmin from Douglas Crockford.

 

2. Disable ViewState on controls and widgets that don't need it.

Yes we all love webforms development and it's ever present ViewState, but you know what, most of the time we don't need it on a Kentico site, or page that doesn't need to do a PostBack to the server. Let's disable it when we have the chance. This will reduce the size of ViewState and make that page download even faster.

Kentico CMS WebPart - Disable ViewState

 

3. Setup Google Analytics.

One of the keys to maintaining a website is knowing what pages get used the most and what pages don’t get used at all. This is true for both big and small websites. Instead of guessing at design decisions on where you think certain elements or functionality should go, place them where they will get used the most by looking at some analytical data.

Sign in to Google Analytics

 

4. Setup Google Webmaster tools.

One of the more impressive, and often least known built in functionality of Kentico is the Google Site Map generator given to you right out of the box. On any Kentico CMS 4.x+ site, hit http://www.somesite.com/cmspages/googlesitemap.aspx. The Kentico system will automatically spit out the correct xml formed document that you can submit to the sitemap section in Google WebMaster tools. This will help you on your Google Search Result ranking.

Sign in to Google WebMaster Tools

 

5. View the Source and Critique it.

This is a big one, and probably should be the most important tip. It will give you some clues on a few things. If you see a big chunk of ViewState please refer to number 2 in this list. Again this probably means that a control or widget did not get set to Disable ViewState.

If you see URL's that are not user or SEO friendly, you might  want to go back into the CMSDesk and verify the links are going to the correct place. I’m not a huge fan of the getdoc method of making links, so generally if I see that then I try to make it into a more friendly link with a URL Alias.

If you see large chunks of inline JavaScript or common JavaScript on multiple pages, that can be moved out to a separate file and minimized the by all means do it. Don’t get too crazy with external files though, if you can get it all into one that is minimized that would be the best.

If you see huge amounts of line breaks or tabs than go back and find out what control is causing it, and remove the whitespace. Templates and/or Transformations can sometimes add extra whitespace, that's a good place to start looking on this one.

 

6. Check your Smart Search Index / Build Status.

If your site uses the Smart Search feature of Kentico, then be aware you need to have the index created. The Kentico documentation is pretty good at laying out what you need to do to make this work.

The button to rebuild a Smart Search Index is located under CMSSiteManager –> Administration –> Smart Search

SmartSearch

 

7. Use the Debug Modes to Check Caching and SQL Queries

The Debug Mode found at CMSSiteManager –> Administration –> System –> Debug, can be invaluable in learning what is getting cached and what is not. An Object or DataSet that is not getting cached is one of the biggest causes of slowness of a Kentico site. Martin Hejtmanek  the CTO of Kentico has a great presentation on caching in Kentico and blog post on debugging in Kentico.

Please remember to turn this off when you are done! 

 

That's all for now

I hope some of these tips will help you out with your Kentico CMS projects and sites. I’d love to hear some feedback on this blog post because it’s my first one on the topic of Kentico, and honestly the first blog post in a long while on any topic for me.


Blog Update

I finally decided it was time to update my blog. So we are now running version 1.6.1 of BlogEngine.Net. So far the upgrade has went well. You might see some small glitches, hopefully I can get them fixed before you notice.


Family Update

Wow I just noticed I havent posted a blog post in um... forever. So yeah a lot is going on. MrsMcbeev just had surgrery to correct a foot/leg problem, and she is recovering nicely from it. Maggs is attempting to lose the diapers. Audrey is talking and has to do everything that Maggie does. I'm busy at work, and hoping MSU makes it to the final four in this year's tournament. Also insanely busy with work. 


Lions Misery

People this is the homepage of www.espn.com right now.

lions_misery

As you can see it's all about the Lions. Oh an not because they are winning, no because they are the worst professional sports team ever. Let that sink in a little bit... worst team ever in the history of any professional sport. That's not something that you can easily accomplish. It makes me sick.

Here's why; I have grown up and rooted for the Lions since I could comprehend football. They are my team in my state. Heck they are my Father's team and his Father's team. And it is painful to go from watching Barry Sanders and being excited every time he touched the ball because you never knew what was going to happen, to this....aberration.

And I want it fixed. I'm sick of people laughing at me for supporting them. I agree with this article 100%. The problems need to fixed from the top. Please for god's sake bring in a new GM who knows what he is doing. PLEASE.

Stop the misery.


Phew! That's quite the title for a blog post. This week I decided to take the plunge and upgrade my main work machine to SQL Server 2008 because SSIS finally supports C# Script Tasks in it.

So After hunting and pecking through all the install screens I finally got to the main pre-install tests. And to my surprise the installer died on the VSShellInstalledRule rule. This is strange because its telling me that I don't have the RTM SP1 installed for Studio, which I have had for a couple months now.

So after checking out this blog post, I still was having no luck,  and no I have never installed any express editions on this machine.

Now this was starting to annoy me. Other fixes I found, including this MSKB support article told me I should uninstall VS 2008 all the way and start over, or not install the BI tools with SQL 2008. Ummm I don't think so.

You see I work various .Net projects for multiple clients. The headache of uninstalling Studio and re-setting up everything gives me nightmares. And the tools are one of the great reasons to upgrade in the first place.

After searching through a ton of install logs, I finally found it referencing some registry keys (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\VS\Servicing\9.0) that said RTM and not SP1. Ah ha I thought. I manually changed them to SP1 and re-ran the check. It worked! or so I thought. The check passed but after running the installation it errored on installing the tools.

After more googling I saw that someone had problems with the TFS plugin to studio. That was the next to go, but again the install errored.

So I started checking other plugins and after un-installing Visual Studio Tools for Applications the installation actually worked.

Wow what a headache.

So if you have the same problem the summary is, un-install any express editions, and / or any old plugins to 2008.


Audrey's First Steps

We heard rumors from Grandma about Audrey walking before. But tonight it is official! Now it's all she wants to do. It's really funny because if she falls down she just says Go! Go! Go! until you start her off again.

Millen reportedly out as Lions president/GM

Praise the Lord!!!! If this is true... I .. I.. don't even know how I could describe how happy I will be. Might this be the last time I say it ? Fire Millen!!

Millen reportedly out as Lions president/GM | The Detroit News | detnews.com


The Lions are a joke

 

...After his third of the day, a few fans ripped off their $80 Lions jerseys in frustration and threw them and their $30 Lions caps onto the field and walked out into the driving rain outside shirtless...

lionsinsider.net - Chance Season Could Spiral Out of Control

Yes you read that correctly, and that's exactly how I felt after watching the worst implosion I have ever seen. Dan and I watched an amazing come back to get them back into the lead at 25-24. And then it happened. I used to believe in Kitna, not sure why, I like him, I think he's a good leader I guess. But now he has to go. Im pretty sure any other QB could match his performance so why not try the other guys.


About Me

I have over 11 years of experience doing this crazy web development thing mainly at BizStream. I'm passionate about software platforms and technologies that can help solve real world problems. I enjoy hanging out with my wife, chasing around my three children and vigorously rooting for the Michigan State Spartans and Detroit Lions. (I know, right? Who still roots for the Lions?)

View Brian McKeiver's profile on LinkedIn

 

PhotoStream

Calendar

<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

last.fm

Kings of LeonCloserabout 21 days ago
.38 SpecialFantasy Girlabout 21 days ago
Dirty Pretty ThingsGin & Milkabout 21 days ago
Little Man TateThis Must Be Loveabout 21 days ago
MilburnBrewsterabout 21 days ago
The HollowaysFit For A Fortnightabout 21 days ago
Kings of LeonI Want Youabout 21 days ago
Hard-FiSuburban Knightsabout 21 days ago
AerosmithJust Push Playabout 21 days ago
DispatchMissionabout 21 days ago

Xbox GamerCard

Offline 8/31/2010 9:08:44 PM Last seen 09/01/10 playing Trials HD