Thursday, July 28, 2016

Tapping on to Duplicate Item pipeline - Sitecore

Tapping Duplicate Item Pipeline


One of the latest requirements and challenging request was to tap on to duplicate item pipeline on latest version of Sitecore.  As of this writing, Sitecore 8.1, update 3.
Every time I have a problem on my hand, to come up with a solution, I clearly imprint on my brain what my goal is, this actually helps find different ways to achieve what you want the system on hand to do.
My goal was to tap on to duplicateitem pipeline somehow to do few renaming and change of few references post duplication of a specific item on the content tree.  The key here is specific item, I dont want this custom code to run if the duplication is done on any other item, so, it is important to know where and how I can patch this to successfully instruct sitecore. "Hey! If content author is duplicating this 'xyz' item only, perform a set of operations"
I ran across couple blogs to start understanding what happens behind the scenes.  Not much of help as either these are outdated and probably not close to what I was looking for....
So, time to write it up, so any one who is looking for some direction on how to tap to duplicate pipeline.


Trials and Failure


I went ahead and looked at my "showconfig.aspx", found the below related config section under processors and this felt like perfect place I could patch on to -


<uiDuplicateItem>
<processor mode="on" type="Sitecore.Shell.Framework.Pipelines.DuplicateItem,Sitecore.Kernel" method="CheckPermissions"/>
<processor mode="on" type="Sitecore.Shell.Framework.Pipelines.DuplicateItem,Sitecore.Kernel" method="GetName"/>
<processor mode="on" type="Sitecore.Buckets.Pipelines.UI.ItemDuplicate, Sitecore.Buckets" method="Execute" patch:source="Sitecore.Buckets.config"/>
<processor mode="on" type="Sitecore.Shell.Framework.Pipelines.DuplicateItem,Sitecore.Kernel" method="Execute"/>
</uiDuplicateItem>

I tried patching to most apt looking processor which is "Sitecore.Shell.Framework.Pipelines.DuplicateItem", did not work. :(

It is because of introduction of buckets which I came across while reading related blogs out there. Great read if you have time.

http://jockstothecore.com/a-tale-of-three-friends-close-look-at-three-sitecore-pipelines/

Based on this article, I patched on to before the buckets related pipeline for duplicate 
that is 'Sitecore.Buckets.Pipelines.UI.ItemDuplicate'

The challenge here was the client args in the info object had array of fields under the item that is to be duplicated which I had no way to overwrite. So, it does not achieve my goal, scrap that. 

Then, I thought I will tap SaveItem pipeline, but, I will loose the context of which item is being duplicated and either way's duplicateitem does not trigger save item pipeline, so that would not work. 

I am hitting walls in every direction, but, I need to keep looking and trying...

Voila Moment!!!!!

I was curious what does Sitecore.Buckets Item Duplicate pipeline does with Client Args as that route made most sense.  It seems only thing the code uses from Client Args was the "Name" for the new item. 
While exploring the code on Kernel dll using reflector, I see that it directly calls Context.Workflow.DuplicateItem(item, args["name")).  This is getting interesting, seems like I see light at the end of the tunnel. 

Explored more deeper, chain of methods called from this point one ->

Item.Duplicate(copyName)
this.CopyTo(parent,copyName)
this.CopyTo(more params)
ItemManager.CopyItem(all params)
Provider.CopyItem(params related)

On derived type of copyItem of Provider, I see something that caught my eye. 
It calls GetDataEngine and proceeding with CopyItem on DataEngine.  Dug more deeper..
It calls CopyItemCommand's Execute, Voila!!! I found my answer. Panicking with excitement, I tried extending CopyItemCommand's prototype using the below kind of config edits 


<database id="master" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
        <Engines.DataEngine.Commands.CopyItemPrototype>       
          <obj type="Yournamespace.ClassName, DLL" />
        </Engines.DataEngine.Commands.CopyItemPrototype>
      </database>

I followed similar syntax from Sitecore.Buckets.Config to make this work.  There is a catch, always make sure you are overriding CreateInstance method and returning your new class in that method, otherwise it will not consider your class as valid prototype and will take the default one. 
Now extend the class "Sitecore.Data.Engines.DataCommands.CopyItemCommand"

It worked!!!!

I could get the source item, destination item(parent), copy ID(new id to be created) and I can extend the Executed method now to add my own business logic.  

Make sure you you call base.Executed() to ensure the base functionality is still in place. 

Good Reads/Helpful Related articles
https://reasoncodeexample.com/2013/01/13/changing-sitecore-item-references-when-creating-copying-duplicating-and-cloning/

http://jockstothecore.com/a-tale-of-three-friends-close-look-at-three-sitecore-pipelines/

http://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2010/11/intercepting-item-updates-with-sitecore.aspx

Tuesday, July 19, 2016

Another reason to get on latest update of VS 2015

Nuget Extension Issue - VS 2015 Update 1

Well, I think it is about time VS pushes notifications to it's users to update to latest update available and recommended. :)

I was having issues downloading Nuget's dependent on my project template on VS 2015 Update 1. After my co-worker mentioned he is using a different update version of VS 2015 he is on.  I wanted to give it a try.  Updated to update 3 and boom it started working.

https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs

May be it will help someone who is using old update of VS 2015 and having the below issue -

Error was -"Object reference not found".

So, basically the project template was trying to download Nugets and each Nuget had multiple dependencies which VS update 1 was not able to deal well.

Other option is to download latest version of Nuget Package Extension, some told me even that worked.

Hope, this helps..



Monday, July 18, 2016

Purpose of Area field on Sitecore 8.1?

So, It all started with an un-answered question on sitecore community on why the 'Area' field does not seem to work on View Rendering.
https://community.sitecore.net/developers/f/8/t/3509

Field In Question





Human tendency is if we are taking pain to enter a value for a field on sitecore, it does do something dynamically.  The first thought is, if I fill in the Area field on Sitecore Rendering Item, It should auto pick the path to my *.cshtml by constructing it rather than depending on us to fill in full path of the view in the Path field.

But, if I tried that it caused error on my end that it can not find the view.
I started reading around to see what is the purpose of this Area field? May be the purpose is bigger/better? I mean sitecore added this in the latest release.

Good Reads Below -
http://www.nonlinearcreations.com/Digital/how-we-think/articles/2015/10/Sitecore-8-1-MVC-Improvements-Area-Support-and-MVC-5-2-3.aspx
https://ctor.io/new-in-sitecore-8-1-mvc-areas/
https://citizensitecore.com/2015/10/26/mvc-areas-in-sitecore-8-1-a-step-by-step-guide/

Based on the blogs, this new token or field value could be used for view resolutions inside your controller or view renderings, but, sitecore would still need full path in the path field.

So, the gist is you read this field as you read any other field on the code.  Only note is if you need to use this field value on code use it by name and not GUID(As it is unique obviously for each rendering).

Something like..Sitecore.Context.Site.Properties["area"];

If you have your own Area Resolving strategy, which by the way you need to plugin properly for it to work, then in your class use the Area value when needed.

Got it! Some purposes that could pay off on adding this new field.  I am still curious to know the ground breaking reason if any that Sitecore added this field.

Anyone???







Friday, July 15, 2016

Sitecore 8.1 Update 3 - Bug on Scheduling Tasks

For my upcoming project, one of the requirement was to run a scheduled job every 24 hours.  Fair enough I hardly remember how to accomplish this as on my previous projects I was using console application with windows scheduler to do the needful.  This time around, I wanted to explore what sitecore offers out of the box for this demands.  It was cool, very simple and easy to do so.


Understanding - My first step 
I explored couple of blogs to gain understanding on how scheduled tasks and commands work on Sitecore.  Please see the references that helped me a lot.

https://sitecorebasics.wordpress.com/2014/08/09/scheduled-task-basics/
https://briancaos.wordpress.com/2011/06/28/run-sitecore-scheduled-task-at-the-same-time-every-day/
https://www.degdigital.com/insights/how-to-create-sitecore-scheduled-task/
For even more deeper understanding and if you have time refer to below as well -
http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2010/11/All-About-Sitecore-Scheduling-Agents-and-Tasks.aspx

Debugging - Crucial One
For triggering the jobs manually, this is for debugging purpose and for us devs with out this, we can not successfully test the code that runs on command trigger.  There are multiple options to do this, I found the below module available on market place, it was very easy to install and fairly simple UI to deal with, I tried others, but, I could not make it to work or documentation was missing some steps.  I recommend below one -
http://sitecoreblog.blogspot.in/2011/07/new-module-on-trac.html
Note - After you install, many newbies who have not worked on Toolbox might not know where this UI get's installed, it is in "All Programs -> ToolBox -> ScheduledTasksUtil .  Click and view all jobs on your instance and trigger any one you wish to debug manually.  Cool! Simple! Isn't it.

Actual Bug  - 

I logged a support ticket for this, I will update this blog post based on sitecore team comments. Though the bug is not huge and has a workaround that we could do for new projects, for teams who might have this issue and if that goes un-recognized could be great deal of problems especially when syncing super important data feed or something.

Here goes the issue -

When I create a scheduled task, there is an option to set the schedule, for example if I need to set a command to run every 24 hours based on documentation by John West, we need to do below as format suggests HH:mm:ss
But, if I have 24 set in the hours, sitecore is reading that as 24 days instead of 24 hours, for any number lesser than 24, it reads correctly as hours.
It does not seem to be an intuitive behavior and looks like a bug while converting hours to days.

On our end, we can proceed by setting this number to less than 24 like 23 as that works fine, but, I wanted to report this regardless as it could be broken on sitecore instances where they had set up a schedule for every 24 hours as this will be running on their end for every 24 days instead of hours.
See some screenshots below.
Example Schedule that has unexpected assignment on schedule -





Loaded up Schedule Object Interval showing 24 days instead of hours. 




Work Around (Update from Sitecore team)

It seems this is how .Net above 3.5 deals with it on Time parse.  See more details below.
https://connect.microsoft.com/VisualStudio/feedback/details/764618/timespan-parse-24-00-00-returns-24-00-00-00-instead-of-throwing-an-overflowexception

On Sitecore side, the format that has to be used on latest versions of .net frame work would be to use below format for 24 hours.
Example - 20160714|21000714|127|1.00:00:00