API Changes in Kentico 8
Improving API to be able to follow the latest trends and make it efficient is an important part of any platform life-cycle. This article will give you more insight into the API changes made in Kentico 8, and also explain the reasons why these changes have been implemented.
Hi There,
It has been a long time since the release of Kentico 7, and exactly 18 months of development for Kentico 8. As we announced a couple of times in the past already, we worked hard on improving the overall architecture and stabilizing the public API of the platform so that it doesn’t change as much in the future as it did in the past.
This process itself, however, comes with actual changes to the API because you can’t make anything better without changing it. So it’s kind of a double-edged sword.
Long story short: It takes some pain now to avoid larger pain in future.
Trust me when I say that we don’t enjoy refactoring very much or changing the API — in essence, this is all actually driven by your feedback and backed by a number of voices.
Have a look at the following feedback example:
http://ideas.kentico.com/forums/239189-kentico-product-ideas/suggestions/452560-start-api-redesign-with-unit-testing-in-mind
Check this one out as well:
http://ideas.kentico.com/forums/239189-kentico-product-ideas/suggestions/389126-support-for-mysql-oracle-and-others
As you can see, these changes truly are supported by
a lot of opinions and votes made by you, our users and partners.
So, even if you don’t enjoy some of the changes that we have had to make right now, trust us, you will appreciate them in the future as they will also allow us to provide you with clear and efficient best practices on customization, development of new modules, and other stuff that you need in order to make your transition between versions smoother. The whole exercise is simply about making things right and getting rid of the legacy obsolete (anti)patterns that no longer align with current trends.
Simply put, we don’t want to stay frozen with what we have now, and become obsolete like dinosaurs (or some of the large well known corporates in the past). We want to be the market leaders, and in order to do so, we first must become innovators.
So the message to you in my introduction above basically is,
“Welcome the changes. Do not fight them. They are good for you!” Now, let me get down to the specifics of what I am talking about.
Number of changes in Kentico 8
If you look at the changes made in Kentico 8 API one-by-one, you will end up with a pretty long list. But if you dig deeper, you will quickly realize that most of them actually follow just a
couple of common patterns, so the number of their resolution types is quite low. Most of them are basically performed through a bulk move of classes from one library to another, changing the namespace name and splitting or merging the static helpers. All of this is part of the API housekeeping to make things more obvious and organized, but they often do not influence your code very much since the resolutions are simple.
Why not Obsolete?
We sometimes get questions as to why we don’t, first, make things Obsolete, and then later let them stick for a while before we remove them. The answer to this question is, “We do, but typically only with minor versions”. The reason for not doing it this way in major versions is actually based on feedback from our partners. As many end clients of our partners often do not upgrade right away to the newest version, but rather align upgrades with redesign of their web sites (which typically happens every 2-3 versions), extending the support for API for just one major version wouldn’t help them, and would actually limit the way in which we can improve and further stabilize the API and best practices.
For instance, things like moving classes to the correct namespaces or libraries would simply not be easily attainable. Also, most of our clients prefer to convert their code right-away because making things obsolete doesn’t really fix the problem… it just postpones the issue, and it’s not very good practice to keep a technical debt that you already know about.
We have announced that the next versions to come will be minor versions (8.1, 8.2, etc.), with a release cycle of three to four months. In order to be more flexible in delivering the improvements, we expect that these versions won’t contain any breaking changes that would prevent a completely automatic update from ensuing, so that future upgrade from Kentico 8 to Kentico 9 isn’t influenced by these minor versions. So the next round of larger changes should be present within the upgrade from Kentico 8.x to 9.0.
Transition from Kentico 7 to Kentico 8
Before I describe the particular changes, let me give you an update on what is going on in Kentico right now in order to help you with the transition. We are now working on a couple of projects:
-
Upgrade tool – Similar to the previous version, we will provide an automated update that will bring your existing database and file system up to date to the new version. This, however, doesn’t cover your custom code, which is why we work on other projects as well
-
Full list of API changes with their resolution – We have always provided an Excel spreadsheet with the API changes, and we are going to provide you with the same list for Kentico 8. Based on the feedback we received, and the number of changes involved, there is a need to provide this listin a much better fashion. So we now actually have an internal application that allows us to provide data and resolution for every single change, and we plan to provide you with this data as an application with a filter by signature, so that you can easily find the resolution for a particular item. This will make your life much easier.
-
Application for detection of changed API in your custom code, and automatic replacements – As the previous list will be data driven (not just text based resolutions), we will be able to provide you with an application (probably a console) that will give you a report on your custom code about which parts of your code need to change and how, which helps you with the transition of your code and estimation of the upgrade costs. We may also be able to cover some of those pattern-based changes automatically and convert the code for you. If not right now, then definitely in the near future.
What is great about these projects is that they are quite general and we will be able to reuse them and make further improvements on them in the next versions, as well to even further simplify the upgrade process in the future.
Typical API changes
Let me now give you an overview of the majority of API changes that happened in Kentico 8. As you will see, there isn’t that large a number of change types involved, and the transition to the new code is also rather simple.
New/Changed libraries and namespaces
The vast majority of changes in Kentico 8 are caused by moving types to correct namespaces and libraries, especially when the previously existing library was a monolithic mixture of various unrelated modules such as library
CMS.CMSHelper.dll. As only a couple of such types altered their names, it is very easy to find out where a particular class has moved. You can either use ReSharper, which gives you hints, or just Kentico API reference to find the class by name in a new namespace:
http://devnet.kentico.com/docs/8_0/api/index.aspx
Note that if your code is in a compiled library, you may need to also add new references to the new Kentico libraries. Namespace always corresponds to the name of the library, therefore it is easy to find the right one.
To give you an idea, and also so that you are able to find the target ones in an easier manner, here are the most important new libraries that we separated based on particular APIs and groups of functionality:
-
CMS.Automation – Base classes for the automation engine.
-
CMS.Core – The very base of the application providing core basic services and discovery.
-
CMS.CustomTables – All classes related to Custom tables.
-
CMS.Globalization – Classes related to geography, e.g. time zones, countries, etc.
-
CMS.Localization – Classes related to cultures and resource strings.
-
CMS.MacroEngine – Everything related to macro (K#) engine.
-
CMS.Modules – Module metadata classes.
-
CMS.OnlineForms – On-line forms (BizForms) classes.
-
CMS.Protection – Classes related to extra protection such as bad words, banned IPs, etc.
-
CMS.Relationships – All classes related to relationship between documents and objects.
-
CMS.Taxonomy – All classes related to taxonomy, which means mainly categories, tags etc.
We also have couple of renamed libraries to better describe their purpose and content. Here are the most usual libraries that you come across:
-
CMS.GlobalHelper -> CMS.Helpers
-
CMS.SettingsProvider -> CMS.Base
-
CMS.SocialNetworking -> CMS.SocialMedia
It is quite easy to guess the right target for most of the previously existing classes, so I won’t describe anymore details for this.
Moving static methods to the right classes
This includes mainly helpers, or static methods that should belong to helpers. Those are mostly the ones that were in namespaces
CMS.SettingsProvider, or
CMS.DataEngine as CMS.SettingsProvider contained some low-level access to database, which now is not needed. All access to DB now starts at the level of CMS.DataEngine, which also makes things more unified across the whole system. We have reviewed the API of such helpers, and made some of the following steps if it was necessary:
-
Moved the method to another helper where it made more sense.
-
Merged two smaller helpers into one so that you don’t need to locate the right one.
-
Split too large helpers into more helpers to narrow down their responsibilities.
Again, you can either use ReSharper, API reference or just Intellisense to find potential targets easily.
Moving object type constants to particular Infos
If you are using any object type constants in the format of
MediaLibraryObjectType.MEDIAFILE, note that these object type classes were completely removed. We moved these constants directly to Info classes for two reasons:
-
To unify the location of these constants for Kentico classes and your custom classes created within custom modules (see https://docs.kentico.com/display/K8/Creating+custom+modules for more details about module and API development)
-
To make clear which Info objects/data they represent when used in the code
So the new way how to reference those constants is as follows:
MediaFileInfo.OBJECT_TYPE
Note that objects with more object types contain additional constants of this sort. We didn’t change any of the constant values, so even if you hard-coded particular values in your code, it will still keep on working.
Library CMS.CMSHelper distributed to module libraries
Since part of our housekeeping is making sure that the system does not behave as a single monolithic application (for both flexibility and maintainability reasons), we got rid of the whole library
CMS.CMSHelper. This helps us to resolve the often asked question “Do I really need to reference that many DLLs even when doing something simple?”
Most of its content was distributed to other libraries just through moving classes, so you can find them easily as discussed above. But there is one specific change you should be aware of, because it is used heavily.
This aforementioned change is a modification to class
CMSContext. This class disappeared from public API (it still exists but is now internal and almost empty just to maintain backward compatibility for macros), and its properties were distributed to other context classes of particular modules.
So when you are searching for the right location, try following classes based on the nature of the particular property you are using:
-
CMS.Community.CommunityContext
-
CMS.DocumentEngine.DocumentContext
-
CMS.Ecommerce.ECommerceContext
-
CMS.Forums.ForumContext
-
CMS.Base.RequestContext
-
CMS.Membership.MembershipContext
-
CMS.OnlineMarketing.OnlineMarketingContext
-
CMS.PortalEngine.DeviceContext
-
CMS.PortalEngine.PortalContext
-
CMS.SiteProvider.SiteContext
-
CMS.Taxonomy.TaxonomyContext
-
CMS.WebAnalytics.AnalyticsContext
I will show you how you can easily create a context class of this sort for your own module in a future article.
Provider API changed to DataQuery
I mentioned this as well as what DataQuery is in my previous article
http://devnet.kentico.com/articles/kentico-8-technology-dataquery, however, just to make sure that you are aware of it (if in case you didn’t read it, for example), I will cover that here as well.
We have changed the way how to query data from providers and removed the cumbersome method calls such as:
var users = UserInfoProvider.GetUsers(where, orderBy, topN, columns);
We have replaced these with a more elegant solution that returns open lazy-loaded query that can be further modified (more information in the mentioned article). The provider now only has a single parameter-less method that gives you all objects, and lets you set further parameters to it.
To convert the previous code to a new version, use the following pattern:
var users = UserInfoProvider.GetUsers()
.Where(where)
.OrderBy(orderBy)
.TopN(topN)
.Columns(columns);
Note a couple of aspects:
-
The return type changed from InfoDataSet<UserInfo> to ObjectQuery<UserInfo>, but they have a very similar interface, so whether you use var or just change the type of your variable, you can still work with the results in the same way (enumerate it, or work with it as a DataSet). I recommend you to use var in this case (and everywhere else where Kentico API returns a more complex type, as it will yield an easier transition in case we have to change anything for something better).
-
This way, you still pass hardcoded where / orderBy / columns to the query, so you may want to take one more step and use parameterization through abstraction of particular methods that you can learn in the previously mentioned article, and as you will learn later as well. The DataQuery provides a way in which you can pass to the method a full where condition, and we plan to remove this option. One reason for that is security due to possible SQL injections. The other one is performance due to query caching on SQL server. We just didn’t want to make these things too complicated for you, until we convert all Kentico API to call itself the right way as well.
-
You don’t need to call methods for parameters that have default values. , for instance when you pass in null values.
We didn’t want to encourage you to use some incomplete method of transition that we would eventually remove anyway, so we didn’t provide you an easier way to do it on purpose. But let me give you a hint in case you decide to use a lot of these calls, and want to postpone this transition for later.
What you can do is provide yourselves with the following extension method:
public static TQuery With<TQuery>(this TQuery query, string where = null, string orderBy = null, int topN = 0, string columns = null)
where TQuery : IDataQuery<TQuery>
{
return query
.Where(where)
.OrderBy(orderBy)
.TopN(topN)
.Columns(columns);
}
Then use much simpler transition of the old code in the following way:
var users = UserInfoProvider.GetUsers().With(where, orderBy, topN, columns);
This way you can just simply insert
„).With(“ to your existing calls. But as I mentioned, we are eventually (I am hoping for Kentico 9) going to drop the support for full string parameters such as the “where” condition, so take that just as a temporary solution in case you get into trouble when converting too much code.
Note how easy extensible DataQuery is without degrading its functionality. Neat, isn’t it?
Similarly, if some of your processes were strongly bound to the original type of the result, you can get the InfoDataSet out of the query this way:
InfoDataSet<UserInfo> users = UserInfoProvider.GetUsers().TypedResult;
We could not provide an implicit cast operator in this case due to a collision with implicit cast to plain DataSet class, which has a higher priority for us in performance-sensitive operations.
Final words
So those were the guidelines that cover the vast majority of the changes in our API that will influence you. As you can see, it is not as bad as it looked in the beginning. The resolution is often just about
adding a using for new namespace,
changing the name of the static class you use or
using var instead of specific type for a method result.
All of that just for the sake of
better Kentico API, which will make you more productive and give you more control over your projects.
I personally think this housekeeping is absolutely worth it, don’t you agree?
Should you have any questions regarding these matters before we release the final list of changes on DevNet as a part of the release of the upgrade, do not hesitate to contact our support at
support@kentico.com, or simply write a comment on this page.
Update: You can find the
full list of API changes here