Some failures to learn from
30th of November, 2016 0 comments

Some failures to learn from

The Nevada dust has settled, everyone is back home and full of impressions from the 404 Conference in Las Vegas, and slowly cooling down from the exciting time we had. Following the theme of the event, here are a few failures I would like to share. Hopefully others can learn from my mistakes, as I certainly did get a lot of value out of the honest experiences that the 404 Conference presenters shared.

Beware of the evil API

During the development phase of an ecommerce website, custom functionality was developed which included a dropdown for selecting a state. Being an Australian-based website, one of the options in the dropdown was 'Western Australia'. As the dropdown option value, the state code of 'WA' was used. As us programmers tend to do, the simplest (and at the time, most logical) solution was chosen for obtaining the StateInfo object from the state code:

public StateInfo StateInfoProvider.GetStateInfoByCode(string stateCode)

Guess what happened when StateInfoProvider.GetStateInfoByCode("WA") was called? The resulting state object was "Washington", not "Western Australia". The GetStateInfoByCode method simply returns the first state object it can find in the database that has the specified state code, regardless of the country. Both "Washington" and "Western Australia" share the same state code of "WA"

Conclusion: Be careful - the API feature you are using might not be doing what you think. In our case,

StateInfoProvider.GetStateInfoByCode("WA")

... had to be replaced with something along the lines of

StateInfoProvider.GetStates()
    .WhereEquals("StateCode", "WA")
    .WhereEquals("CountryID", 284)
    .FirstObject

Reserved names

I was approached by a team member with a very interesting problem. The setup included a custom class with a "CommentArticleID" field, which was a foreign key reference to pages. To retrieve the data, the good old InfoProvider was used.

CommentInfoProvider.GetComments().WhereEquals("CommentArticleID", 5);

The article page with the ID of 5 was published, and the InfoProvider was returning data. Surprisingly enough, for an unpublished article page, the InfoProvider was not returning any results.

This didn't make sense, so we thought about it... Could Kentico have some hidden version 9 smarts, where the InfoProvider is actually aware that the CommentArticleID field is a foreign key reference to a page? Is the InfoProvider automatically limiting the results for published pages only? How could we prevent it from doing so?

Next step was to look at the actual SQL query that the InfoProvider is generating. Of course, we expected something along the lines of:

DECLARE @CommentArticleID INT = 5;

SELECT * FROM ABC_Comments WHERE CommentArticleID = @CommentArticleID;

We retrieved the query text:

var queryText = CommentInfoProvider.GetComments().WhereEquals("CommentArticleID", 5).GetFullQueryText();

This was the actual SQL query:

DECLARE @CommentArticleID INT = 5;

SELECT * FROM ABC_Comments
  INNER JOIN ABC_Article ON ArticleID = CommentArticleID
  INNER JOIN View_CMS_Tree_Joined ON DocumentForeignKeyValue = ArticleID
     AND ClassName = 'ABC.Article'
WHERE ((DocumentPublishFrom IS NULL) OR (DocumentPublishFrom <= GETDATE()))
  AND ((DocumentPublishTo IS NULL) OR (DocumentPublishTo >= GETDATE()))
  AND CommentArticleID = @CommentArticleID

The query was named selectall, which is a reserved name, and is picked up by the InfoProvider. This was, of course, purely coincidental, and steered us towards overthinking the cause of the issue.

Conclusion: Follow the rules of naming in Kentico, and make sure you are up-to-date with the reserved naming.

DocumentEvents and Workflow

This failure is fairly obvious and does not need "detective work" as the ones mentioned above, however it can happen in the wrong time and cause headaches.

A lot of times we use the DocumentEvents global events, to trigger custom functionality in the event of creation and changes of pages.

DocumentEvents.Insert.After += Document_Insert_After;
DocumentEvents.Update.After += Document_Update_After;

This works well until we get a phone call from the client, asking "can we turn on the workflow now?".

When writing these event handler methods, we usually consider the pages being published immediately, and we forget about workflow. The workflow is enabled, and our custom event handlers misbehave. That's when we start the journey of implementing other event handlers, such as WorkflowEvents.Publish.After.

Conclusion: Always plan out your DocumentEvents event handlers, and think about the consequences of enabling a workflow on the pages that are relevant to your event handlers.

Written by Kristian Bortnik


Tags

Comments