November, 2008 Archives
Nov
EPiServer CMS 5 Certified Developer
by Mikael Lundin in Technicalities
Yesterday I was over at Cornerstone for EPiServer certification. It involves taking a test proving that you know everything about EPiServer that there is to know. The test was one of those standard badly written education applications with a web interface, option questions where one or several answers could be correct. Mostly like the driving license theory exam we have here in Sweden.
Even though I passed the test I think it was way too hard. Most questions were really hardcore stuff that you only could have known if you’ve been deep down in the EPiServer SDK doing reflector on EPiServer.dll to get out the answers.
If you plan to get certified these areas are a point of interest
- How to configure cache in EPiServer and what effect each configuration option has.
- How to use filters in EPiServer. What impact has a filter in a SearchPageDataSource and what if you put a filter on a PageDataCollection. How does the event model work around filters? What are the standrard filters in EPiServer?
- How do Virtual Path Provider work and what providers exist in EPiServer. What differs between the providers and what events may be triggered on the providers. What is special about UnifiedFile/Directory and what events may be triggered on those.
- Membership/Role-providers, how do they work? What is special about WindowsMembershipProvider, SqlServerMembershipProvider and ActiveDirectoryMembershipProvider?
- Learn everything there is to know about every configuration option in EPiServer configuration. If you know this you will have no problem with the exam.
- FriendlyURLRewriter, IdentityURLRewriter and NullURLRewriter. What is the difference between them, and when do you need to use what provider?
- How do check if a user has access to a certain page? How do you set access to pages in EPiServer?
- What events are involved in an XForm? Can you change the fields of an XForm from code behind? How?
- How does search work in EPiServer? Search in VPP and options to SearchDataSource.
- How does globalization work in EPiServer? What happens if you turn it off? How do pages that does not exist in current language behave? How do you see that a page is translated or not? How do you from code behind get a page in a specific culture?
- How do you configure mirroring? What does the different options in mirroring affect?
- Plugins and plugin areas. What enumeration would you use to get the plugin to appear where you want? Also, how you add a plugin to the project.
- How do you create a scheduled job and what makes sure that it runs?
- What if you need to store more information about a user than EPiServer allows you too. How do you add that information and where is it stored?
- What are Log Analyzers, and how do you configure them?
As you see this covers pretty much all of EPiServer API. You need to know it all in detail if you want to get a good score on the exam. A good guideline is to study the EPiServer SDK API chm-file and those examples in there, and then to write examples of all the different functionality above. Also, take a look through the whitepapers because I think there were at least one question for each of them.
If anyone at EPiServer dislikes what I’m doing here, sharing knowledge about the exam they are quite naivĂ« to think that people don’t talk to each other. The exam was too hard to just study and pass. You need to work with the framework for a while before you have the proper knowledge to get the required 60% correct answers.
Nov
EPiServer: Page Not Found!
by Mikael Lundin in Programming
In the latest version of EPiServer CMS 5 R2 they released not only a bunch of new stuff, but also changes in the already established interfaces. As an EPiServer consultant that works with both developing websites and also extending the CMS with my own extensions, this made me cry.
One of the more brutal changes for my extensions were that IPageStore was deleted and replaced with the more minimalistic IPageSource. Since almost all my functionality was working with IPageStore, I had to recreate the whole thing now with IPageSource in mind.
Another thing that me and a fellow developer noticed were the change of behaviour in DataFactory.GetPage(). Previously you would get null if you tried to call GetPage() with ID of a page that didn’t exist in the system. Now they’ve changed it to throwing PageNotFoundException. Not a small change, since GetPage() is probably the most used method in the whole framework.
I see where they’re going with it. “They ask for a specific page, with a specific ID. If it is not found in the system, an exception has occured!” But then, I would expect to have a PageExists() method, so I could query the framework if the page exists before I try to get it with GetPage(), but no.
This leads you to implement rubbish extension methods like this
public static PageExists(this DataFactory instance, PageReference pageLink)
{
try { DataFactory.Instance.GetPage(pageLink); return true; }
catch (PageNotFoundException) { return false; }
}
Please tell me if you know any better way to accomplish this.
Well, they didn’t just make my code buggy with this release but also their own. Take SubscriptionJob for instance. It still does GetPage() with a null check to see if the page that a user is subscribing to still exists in the system. This will make the subscription job throw an exception if any page that someone is subscribing to is ever deleted (don’t empty your wastebaskets!).
I wrote the following fix for this earlier today
public class Global : EPiServer.Global
{
public void Application_Start(object sender, EventArgs e)
{
DataFactory.Instance.DeletingPage += new PageEventHandler(UnsubscribePage);
}
public static void UnsubscribePage(object sender, PageEventArgs e)
{
int i = 0;
int totalPages = 0;
ProfileInfoCollection profiles =
ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All, i++, 100, out totalPages);
foreach (ProfileInfo profile in profiles)
{
EPiServerProfile epProfile = EPiServerProfile.Get(profile.UserName);
epProfile.SubscriptionInfo.UnSubscribe(e.PageLink);
}
}
}
You register a method on the DeletingPage event on your DataFactory. In that method you unsubscribe the page that is being deleted from every user in the system. This way, a page is unsubscribed before it disappears from the system.
I would rather see EPiServer test their own software before they release it. Bugs like these are embarrasing and they indicates that EPiServer doesn’t use or properly test their own framework.
Nov
Untestable code
by Mikael Lundin in Programming
This friday we had a discussion about unit tests and what is considered to be untestable code. I claimed that some code is untestable and met heavy resistance.
One of the blogs I read just threw me a good example of when unit tests are useless.
Would you find that bug using unit testing? I would say not, because you would have to start up a lot of threads to encounter the bug. Maybe if I knew that this was a place where many threads would meet and operate simultaneously, but I have to admit that most of the time I forget about thread safety and would not write unit tests for it, if it wasn’t obvious.
Would you find that bug using integration testing? (testing how parts of the system interact with other parts of the system) If one of these parts fire up a lot of threads that will execute on that code you might be able to find the bug through integration testing, but threading in an integration testing environment and threading in a real user driven environment are two different things. Where a computer fires events, code will be run in a neat order, compared to when a user fire events (that start threads) which would be much more chaotic.
Would you find this bug in system testing? Probably. That depends on if one user is enough to trigger the bug or if you need to have several users to get the amount of threads for the bug to appear.
Would this appear in production where you have 100 people running your software at the same time? Yep.
Back to the discussion that we had this friday. Is there any untestable code? My answer is no. You can do excessive unit testing and actually test every possiblity there is, but is it wise? No.
- The cost of testing all code is so dramatic it would make your project manager choke.
- For every test you write you specify that software that you’re testing. Overspecification will make your tests break for every little change that you do to your SUT (system under test) and this will make test maintenance cost more in the long run than debugging legacy code (code without tests).
All code is testable, but untestable code is not worth the cost. Multithreaded code is one scenario where you can’t test every possibility. Another complex situation is when you’re directly using a 3rd party library with bad design. (EPiServer) There are means to get around that too with proxy classes and what not, but we have to ask ourselves once again – is time spend on unit tests time won in debugging?