Friday, October 14, 2011

EPiServer 6.0 compare bug

I've spent most of today, and a couple of hours yesterday, to figure out a weird problem with the function that allow you to compare two versions of a page in the EPiServer 6.0 edit mode. As soon as I clicked the compare button I got the YSOD telling me that a NullReferenceException was thrown from the method ComputeVaryCacheKey deep down in the ASP.NET rendering.

I hooked up the debugger and found that everything seemed to be in order. Altho, we had a few customized renderings in the chain so I started by disabling them one by one to find the cause. Once they were all removed I still had the problem tho, so I started on another track. Next thing I did was to look at the output caching used. Starting with simplifying the GetVaryByCustomString method in Global.asax so it should be almost impossible to have a problem there didn't help. Next thing was removing the OutputCache directives on my controls one by one and in the end - bingo! When the last OutputCache directive was removed I got some other error instead from the compare button.

So it comes down to that adding an OutputCache directive with VaryByCustom would make that ComputeVaryCacheKey crash when trying to compare two pages... I really need my output caching, but for the sake of coming to the bottom of this I left them out looking at the new error message. Maybe it could be the root course and if that was solved I could add the caching again?

The new error said "']]>' is not allowed within '<!CDATA[' blocks" or something like that. Well, fair enough. I looked at the source of the page being compared and there were a couple of CDATA blocks in the scripts generated by ASP.NET but none of them seemed to be malformed. At this point I decided to fire up another EPiServer site and see if the CDATA blocks looked the same, and if they would like being compared on that site. The CDATA blocks looked the same and they did like being compared in that context... Odd. Here I decided to add the OutputCache directive to a control on this site and see if it would work here - And it DID! There was a difference tho - this site was build on EPiServer 6 R2.

At this point I contacted the EPiServer support that within an hour reported back to me that this was a known bug in EPiServer 6.0 that had been solved in R2. The general advise was to upgrade to R2, but in case I couldn't do that I also was send a custom "CompareProvider" written by the support guy that should work with 6.0. So I put that in the bin directory, configured the site as he instructed me for activating this new provider and gave it a go. I still got that "']]>' is not allowed within '<!CDATA[' blocks"... but the good part was that I could add my OutputCache directives again and still getting that error!

Well, now at least I had my own custom code running closer to the problem. I reflected the provider that the support guy sent me and it was only one class. I copied the code to a class in my own project allowing me to set a breakpoint in there. When I had the code it was also obvious that the CDATA issue was addressed in it, but apparently it didn't address the problem well enough. I started by just removing the CDATA start and end block from the input to the compare function and then it worked! Or well, kind of. It didn't seem to have support for css being added with @import so I got a comparison of the page without styling... still, it was the best yet!

Hacking away even more I hardcoded an addition of the primary css to the source, and now it looked good too! A bit too hacky tho, for my taste, it struck me that I could reflect the source from the EPiServer 6 R2 binaries to see how they solved it there. The first line in that version was the Obsolete attribute - use "HtmlDiffProvider" instead it said. Wonder if that works with 6.0 I pondered, and reflected that source and added it to my project next to the code from the support guy. Then executed... and boom! That first NullReferenceException from the caching again! Dang. But, with the code from these two providers I managed to create a one provider that worked fine with EPiServer 6.0!

During this entire episode I did of course do a lot of searching on the web for guidance... getting none! Hence I decided to write this post to help the next person that enters this moat. It's not your fault! It's a bug in the platform! Stop wasting your time looking for problems in your project, and instead add your own CompareProvider.

No comments: