Changes in the API from version Kentico CMS 5.5 R2 to 6

   —   

Since Kentico CMS 6 is a huge release, we had also spent a lot of time on reviewing the API. Let's see what changes you may expect and how to update your custom code.

Hi there,

As our solution grew, some of the API and method headers became too old-fashioned and needed to be reviewed. We didn't wan't to do these general changes across multiple versions so we decided to do this in this major release at once.

Major changes

There are some major changes that have effect on a lot of code in all modules, or particular namespaces.

Removed parameters and properties - GeneralConnection / IDataConnection

If you used our code, you probably noticed that some of our methods had the connection parameter or a connection property, and with earlier versions, you had to assign the same connection object everywhere to write the code that was working correctly with transactions. An example of such method is following:

UserInfoProvider.GetUserInfo(int userId, GeneralConnection conn)

This not only made the code very complex, but it also was very hard to maintain. In version 5.0 we introduced the CMSConnectionScope and CMSTransactionScope that is able to maintain the connection object through the scope of a code block (for the life time of the scope object). You can see more details on how this works here:

http://devnet.kentico.com/Blogs/Martin-Hejtmanek/January-2010/Deep-dive---New-transaction-management-in-5-0.aspx

Having this, all the connection parameters are not needed anymore and we removed them, so you can simply remove them from all your code. You may think about how you now say that all calls in your code block should use the same connection ... and the answer is that you don't need to care.

Kentico CMS 6 goes even further, and introduces a single connection per request (thread). Previously, the system used single connection per connection scope (code block) or per database call, which caused quite a heavy overhead on the connection pool.

Ahother thing is making a connection to a different database. This is also much simpler, the CMSConnectionScope class now supports nested scopes, so you can simply put the connection scope to your code, using another connection string, and that code block will automatically use that connection. Everything not in particular connection scope is using the request connection. If you used our API against other databases, then just put your code in a connection scope created with that connection or connection string.

Just one note: Some of the system objects are cached within the memory, either cache or as static properties (e.g. stylesheets, web parts, settings, but also many more), so even with version 6, you first get the result from memory, and this cache doesn't consider the connection scopes, so you still shouldn't use the connection scopes as a switch between two CMS context from different databases (in that case). I recommend to only use ExecuteQuery methods if you connect to other database. We should handle this in version 7 and it should also be able to provide a way how to connect single application instance to a several databases based on domain name or whatever.

Removed parameters - object[,] parameters

We have done several mistakes in the past regarding the friendliness of the API, and they cover non-typed collections and object arrays. You technically need to know what to put in them so the calls work properly. We already did some of the changes, typically by changing a typed arrays to a generic list, but they are quite minor. More complex change that we did is replacing the two-dimensional object array that was used for parameters for the query with  a new class called QueryDataParameters which provider much nicer way how to work with query parameters, here is some example of the code:

Old code:

object[,] parameters = new object[3, 3];
parameters[0, 0] = "@UserID";
parameters[0, 1] = userId;
parameters[1, 0] = "@Points";
parameters[1, 1] = points;
parameters[2, 0] = "@Type";
parameters[2, 1] = Convert.ToInt32(type);

// Update user counts and add activity points
GeneralConnection conn = ConnectionHelper.GetConnection();
conn.ExecuteQuery("cms.user.UpdateUserCounts", parameters);


New code:

QueryDataParameters parameters = new QueryDataParameters();
parameters.Add("@UserID", userId);
parameters.Add("@Points", points);
parameters.Add("@Type", Convert.ToInt32(type));

 
// Update user counts and add activity points
ConnectionHelper.ExecuteQuery("cms.user.UpdateUserCounts", parameters);
You can also see here how we got rid of the connection, you can simply call the ExecuteQuery and other methods from ConnectionHelper. Isn't it much better?

Removed interface - IInfoObject

Believe it or not, we have had a unified way how to treat object since I think version 3.1. All objects, except documents were implementing interface IInfoObject which we were using to access general properties and hiearchy of the objects with Import/Export and Staging modules. In fact, this is also used in the Import toolkit application, you wouldn't believe how simple it's code is.

Anyway, we have done a serious review of the object API, making it less confusing for the end developer that doesn't care about the general properties that he has available with nice names anyway. This results in replacing the IInfoObject interface by the abstract class BaseInfo, so anywhere you used IInfoObject, simply use BaseInfo instead. In case you used the general properties, all objects now have the property Generalized, through which you can access these general properties. It is basically a wrapper that exposes them.

I will cover this in more details in one of my next articles, where I will explain you the new API.

Removed or changed namespaces - CMS.Staging, CMS.IDataConnectionLibrary,

To make things more clear in the API, due to the new Integration bus feature and object versioning, we had to rename the CMS.Staging namespace to CMS.Synchronization to better match what it actually serves for. You simply need to change your usings to the new namespace.

The namespace and library CMS.IDataConnectionLibrary was joined to the namespace CMS.SettingsProvider, because due to connection changes, it was not needed anymore as a separate
library.

Also, the classes from namespace CMS.FileManager were moved to the namespace and library CMS.TreeEngine so we can provide closer API connection of documents and their attachments.

All these namespaces are still available, just empty, so if you are using both using of that namespace and the new one, nothing changes for you.

Minor changes

The other changes mostly regard just small changes to particular methods, either because we realized that some of the methods do not make sense for you in that particular form, or because new features requires more parameters to specify what exactly is the wanted result. Here you can find the complete list of changes in the API:

http://www.kentico.com/Downloads/KenticoCMS_6_API_Changes.xlsx (66 kB)

As you can see, most of the changes are in E-commerce module, that is caused by tha fact that we had to completely change the customization model as you could learn earlier:

http://devnet.kentico.com/Blogs/Petr-Vozak/October-2011/E-commerce-6--New-customization-model.aspx

Next plan

We still continue to improve our API, so you may await some changes even in the future. The fact is that we don't really see how much you are writing custom code, and how much these changes effect you, so it is sometime hard for us to make decision between nicer and clean API for new code, or backward compatibility for the old code.

Please let us know in the comments how you feel about it, and if you write custom code, which modules it typically covers and what are the items that should be best backward compatible.
Share this article on   LinkedIn Google+

Martin Hejtmanek

Hi, I am the CTO of Kentico and I will be constantly providing you the information about current development process and other interesting technical things you might want to know about Kentico.

Comments

Martin Hejtmanek commented on

Hi Jeroen,

The best way for this is to pick up the connection from the ConnectionHelper, which will give you the request connection. This is in fact what the static methods do, we just do not have the mirrors for the other methods to keep it simple (99% of time you just need to read the data)

var conn = ConnectionHelper.GetConnection();
conn.ExecuteNonQuery(...);

Jeroen Fürst commented on

Hi Martin,

Great post! What is the best practise for calling methods like ExecuteScalar and ExecuteNonQuery? Because I don't see them in the ConnectionHelper...

Cheers!
Jeroen