Showing posts with label EPiServer. Show all posts
Showing posts with label EPiServer. Show all posts

Monday, August 2, 2010

A simple, little web load tool

There are many ways of doing performance testing of web applications. In the good ol’ days I remember starting up Microsofts Application Center Test (ACT) and recording some vbscripts that could later be executed. Nowadays ACT is a lot sexier – but now it comes with Visual Studio 2010 but unfortunately only in Ultimate edition. I tried to persuade my wife to spend the $11000 on the ultimate edition – but she failed to see why this was more important than buying her a car.

Another good option is to use WebLoad. It’s a neat tool – and even if you buy it (to actually get a compiled and running version instead of the do-it-yourself-open-source) it still comes at a more decent price point. I recently played around with it – and it does solve a lot of your performance testing needs – but it’s almost a bit too much overkill for my need (which is essentially to find out how many request/s a web site can handle). I also didn’t like that it hijacked all my browsers and forced them to go through a proxy (in order for it to record what was going on) – and then failing to reset the proxy selection afterwards.

In the end I decided to spend the 30 min it would take to do a simple little performance tester of my own – that does exactly what I want it to.

I came up with AWebLoadTesting which is a compact and ultra-simple console app. It takes an input file which is essentially a text file with a list of urls to visit for each visitor during the test, an output filename – in which it will put a csv file with saved statistics – and that’s about it. If you need to you can also specify a hostname to run the test against – and even a custom UserAgent for the requests.

image

When it starts you have 0 visitors active. Then, by pressing “+” you can add visitors one at a time – and by pressing “1” and “5” you can add chunks of 10 or 50 visitors at a time. Each visitor is started in its own thread and will continuously go through the urls from the input file again and again.

“u” updates your view, “r” resets the counters", “s” saves the current data to the output file, “-“ removes a visitor” and of course “q” quits.

You’ll constantly be presented with the measured numbers: Time measured (s), Requests / s, Visitor count, Max load time, average load time and min. load time. On top of that it will show you a prioritized list of which urls are the slowest to return. That’s it.

The screenshot above is a test against a local EPiServer CMS 6.0 web site on my laptop, running with ASP.NET caching turned on (Set cache-expiration to 1h in episerver.config, site settings).

Download the binary here and the entire project here. Use AS-IS, LGPL 2.0, Quick&Dirty.

Monday, May 17, 2010

And a (non-virtual) role change

May 1st I arrived back in Denmark after spending a year in the US assisting with assembling and training the GREAT team that we have there now as well as working with some truly skilled and passionate partners (you know who you are). I must say it’s been a great learning experience as well as a very exciting time – both for EPiServer but also for me personally.

Now, that I’m back in the old world again it seemed like a good time to try a new angle at producing great software – and as luck would have it I was offered to try on the shoes as product manager. Even though I’ve always had a deep passion for coding I’d love a chance to really influence the future of creating great web sites in a way that only a product manager at EPiServer can do it.

I believe that the most important job for any software product company is to create software that solves real problems that people in their markets have. This is the key factor that more than anything should be driving both the development and sales process – solving real problems for real people. And of course solving the problems in a carefully designed and planned manner so the solutions adapts to the users needs and skills – and not the other way around. Too many times have I seen countless examples of technology and features in various products (in all industries) that are there for no other other reason than adding a feature – but not solving any real problems. Flashy as some of it may seem it’s still essentially useless. The consequence: development time that could have been spend solving problems wasted, and users confused with features that doesn’t make sense.

Luckily EPiServers history shows that we have been very successful in solving real problems. And I believe that’s why so many web sites, editors, developers and marketing people use our entire product portfolio as their platform of choice today. But of course we can still do even better. Especially with YOUR help. I want to learn how you use EPiServer CMS. And even if you don’t use it – tell me how you manage your online content and which problems we could solve for you.

Wednesday, December 23, 2009

Visual Studio 2008: Application Cannot Start

 

I got this annoying error, every time I tried to run my VS2008 SP1 in Administrator mode (which is needed to avoid the “Failed to map the path '/'.” when running an EPiServer site in visual studios web server). Some google searches brought to outdated microsoft material – but luckily also to Alex Riley’s helpful post: https://www.21concepts.com/Blog/EntryId/10/Visual-Studio-2005-2008-The-application-cannot-start.aspx.

On my win7 x64, it turned out (thanks procmon) that my visual studio was looking for C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\dte80a.olb – and once I copied that from C:\Program Files (x86)\Common Files\microsoft shared\MSEnv all was well.

Sunday, June 21, 2009

Trends in Web Content Management

After a couple of weeks of attending various web content management conferences (GilbaneSF and Web Content in Chicago) and talking to a lot of people more clever than I, I figured that a summarizing blog post might be in order. These are some of the trends I spotted.

 

Social

Facebook, Twitter, Flickr have paved the way – now everybody wants user generated content. It seems as if most companies has figured out that visitors that contribute with content are dedicated visitors – and who wouldn’t want those?! Most CMS vendors has forums / blog functionality built-in – and a handful have gone all the way with full-sized communities containing clubs, my-page, videos, friends, social graphs, you name it (including EPiServer). A lot of the stuff isn’t new – forums and public profiles were common even during those delightful years of BBS’in in the eighties and early nineties. And during the Web 2.0 era a few years ago it boomed. It’s first now, however, that people are really considering when to use which features – and when not to use it. Perhaps it is really time to start use this technology not just “because we can” but “because it makes sense”. This might just be when Web 2.0 turns profitable.

 

Personalization

Personalization has been hot for a couple of years now. Pioneered by companies such as Amazon, Netflix, etc. companies are now starting to see real business value in personalizing their content. The term is used to cover a lot of different technologies and usages however. Everything from changing the language of the website to automatically suggesting products that the current user is interested in – is some kind of personalization. Even silly things such as letting the user customize the style or background color of the website is getting popular.

Again Facebook has turned out to be somewhat of a thought leader – adds shown there are totally personalized to your characteristics increasing the possibility of a click/purchase.

Most CMS vendors have some sort of way to enable simple personalization – like the ability to save key/value fields about each visitor and that way allow the implementation to build up a profile. But after what I’ve been able to find out nobody has gone beyond that – which means that most of the personalization work done is done in the actual implementations of websites and not as a standardized feature in the content management systems. In a few cases the search engines used on the websites actually comes with more build-in personalization features than the CMS.

 

Mobile

Mostly due to the iPhone and increased 3G/HDSPA/edge coverage the web is no longer something that’s just meant for regular desktop/laptop computers. In fact in Asia, most internet usage is coming from mobile devices. So every CMS vendor is coming up with strategies on how they can deliver content across platforms. To be able to manage mobile content is a MUST these days – and the approaches vary from automatically transforming the html to supporting multiple rendering methods. A series of niche-players purely focusing on extending the mobile abilities of mainstream CMSs have already emerged.

 

Translation & multiple languages

As the world gets smaller and economies collapse in the english speaking world a lot of focus has turned to new, emerging markets in the east. This brings with it an increased focus on translation services and the CMSs ability to handle multiple languages. While European vendors have been used to the multi-language-challenges for years, it’s still a somewhat new challenge to US websites and systems. And once the system is in place, the actual translation begins. And in spite of what you might think it’s not just about changing the texts on a page. Multi language often means multi culture. Pictures, expressions, analogies and site structure often needs to be adapted. Some languages require right-to-left alignment. Illustrative pictures that are innocent in one culture can be highly offensive in another. A huge market for translation services and culture consultancy has emerged – and it seemed that no matter where you’d turn a Gilbane a friendly guy from a translation company would be there :-)

 

Connecting

I remember a day, not too long ago when I learned that a major danish company had an entire department of secretaries hired to take printouts from their ordering system and type them into their hour-management system, their CRM system and their invoicing system manually. None of the systems could interact in spite of them being based on the same platform – heck, even on the same servers.

Hopefully we’ll soon see the end of those days. There is a lot of focus on interoperability and connecting different systems – especially in the content management industry. Vendors are opening up their API’s, supplying web services and even building connectors to various systems. Most popular are connectors to enterprise search, sharepoint and crm systems like Salesforce and Microsoft CRM. Many implementations feature integrations to backend commerce-systems, product databases and invoicing systems – and we are starting to see a tendency to more standardized connectors as the systems mature.

EPiServer went down that road long ago, with Virtual path providers, Content Channels, open API, Microsoft CRM connector, Salesforce connector, EPiMore partner program and in version 5.2 we came out with PageProviders to connect live to any other datasource.

It’s easy to understand the popularity of this – ROI’s are easily measured in the number of work hours saved from being wasted on manually synchronizing data.

As a result of these efforts we are also seeing new protocols and standards emerge. Since it was proposed in august there has been a lot of buzz around CMIS (Content Management Interoperability Services) and many vendors are starting prototyping projects to be CMIS compliant when/if it officially becomes a standard. I talked to quite a few people about it and of course people are afraid that it will suffer from YASS (Yet Another Standard Syndrome) and die down – but still like the idea of a common way to integrate with other ECMs – or let other systems integrate with theirs. Together with a handful of others I’ve started the NCMIS project recently to see if we can scrape together a cross-vendor team interested in making a shared, open source .NET library/toolbox to help everybody adapt their systems to CMIS.

 

Collaboration on Content Creation 

Ok – I admit – to call this a trend just yet might be taking a step too far. But I predict that this is a trend we’ll see soon. When Google Wave launches for real I could imagine people getting used to constantly collaborate on construct contents. Today most CMS systems lack features that allows concurrent editors to actively work together on creating a piece of content – at most there’ll be a check-in / check-out functionality to avoid overriding each others changes. But wait and see!

 

Measurability

The last trend I’ll mention is probably one of the most important trends. Today it’s not longer enough for a feature on a website to be cool in a geeky sort of way. Today you need to proof that it’s cool. Most vendors today integrate with some sort of web statistics tool to show basic stats for the website – but we’ll see even more very soon. Many vendors are looking towards marketing engines, A/B testing, landing page optimization as built-in features that will allow website owners to test how well a given change to a website works on the visitors. Sometimes even simple changes in the text of a link can make the difference between success and failure for a website – and you’ll need to be able to measure it. Perhaps it’s the maturing market and technologies – perhaps it’s the collapse of economy, but measuring & tracking – often realtime – what’s going on on your website is definitely part of the current and future.

Sunday, January 4, 2009

WikiX - a Wiki for EPiServer CMS

Just before Christmas I was part of a team that launched WikiX an Open Source Wiki for EPiServer CMS 5 R2. Even though it's still in beta, it is actually really nice with a lot of cool features. WikiX is based on some of the thoughts and ideas presented here: http://allantech.blogspot.com/2008/10/wiki-vs-cms-difference-is-psychological.html.

wikix

See the announcement: http://labs.episerver.com/en/Blogs/Allan/Dates/112230/12/Announcement-WikiX-is-here/

Try it live here: http://wiki.demo.episerver.com/

Download it from Codeplex:http://www.codeplex.com/EPiServerWiki

Saturday, October 18, 2008

Wiki vs CMS - the difference is psychological

When I started in EPiServer AB one of my first tasks was to "make a wiki plugin for EPiServer". Naturally, being new in my job, I enthusiastically started working. However, it pretty soon dawned on my that I didn't know what a Wiki really was. Sure, I use wikipedia daily and understand how it works, I know that "Wiki" means "fast" in Hawaiian, but it wasn't really that obvious to see what the difference is between a CMS like EPiServer CMS and a Wiki. I ended up writing an internal RFC on the subject, and awaited comments while I moved on to tons of other tasks, piling up on my brand new desk.
Around half a year later, I'm in a small but luxurious hotel in the Stockholm archipelago together with the rest of the EPiServer Research team, brainstorming on which new prototypes we should make for our big partner event in june. Again, the Wiki came in to play, and I spend a week or so making a working prototype of it, which I later demo'ed at the Partner Summit and hopefully soon will find time to finalize and ship as open source...but I digress. After reading Deane Barkers excellent blog post on the subject I figured I might share my views as well. So here goes:

 

"A wiki is a medium which can be edited by anyone with access to it, and provides an easy method for linking from one page to another." (Wikipedia)

"Contrary to their reputation, Wikis are content management systems that can be managed. They simply take a different approach to content management by choosing to emphasize speed and flexibility rather than strict controls." (CMSWatch)

So, what I really see initially is that a Wiki is a Content Management system focused on collaboration and knowledge sharing. A typical CMS has a some editors and many readers, where a Wiki has many editors and many readers. Not all that much of a feature. Just as Deane I've also looked at some of the key wiki features:

  1. The name of an article is embedded in the hyperlink.
  2. Articles can be created or edited at anytime by anyone (with certain limitations for protected articles).
  3. Articles are editable through the web browser.
  4. Each article provides one-click access to the history/versioning page, which also supports version differencing ("diff") and retrieving prior versions.
  5. The most recent additions/modifications of articles can be monitored actively or passively.
  6. Easy revert of changes is possible.
    On top of those features I would also include:
  7. Easy linking
  8. Easy creation of new pages

(Wikipedia's list of Wiki features)

All features that's either out-of-the-box or just a matter of configuration in any state-of-the-art CMS, like EPiServer CMS.
So, is a CMS = Wiki ? I didn't really see the difference until after I made a prototype and allowed my coworkers to start to use it.

The prototype I made was based on EPiServer CMS, and consisted of the following:

  • A UI that looks like wikipedia
  • View-mode editing of pages
  • Support for WikiSyntax ( like [[links]], etc.)
  • Ability to create a new page on-the-fly if there's a link to a page that doesn't exist.
  • Each page consists of X elements that can be edited independently
  • View-mode version control
  • Discussion Forum for each article
  • Handling of multiple concurrent edits
  • etc.

The moment I had a prototype up and running it didn't take me long to see the strength of these relatively small changes. It's addictive.
So, I realized that the difference between a CMS and a Wiki is really psychological. A Wiki's strength is fast and quick knowledge sharing - with everybody contributing to gather all their knowledge together. Why? A CMS is typically used for websites and/or intranets. Text-writers and editors use it to publish and structure their perfectly written articles. And here is the core of it all....A wiki doesn't need to contain perfect, complete articles. In the nature of a wiki anyone can add their knowledge instantly - either to existing articles or by beginning new ones - but without the obligation to finish them. And hence people are much more likely to start sharing their information. Still not with me? Here's an example: My knowledge of about the country of Norway is limited. If I were to write an article (or a blog post) on Norway I would have to do a lot of researching and then spend a lot of time writing and compiling all this knowledge. End result: I'd never get it done (mostly because I'm lazy, but also because I'm busy and not all that interested in the subject (sorry, Steve)). However, on a Wiki I wouldn't mind at all adding the few things I know about Norway to an existing (or non-existing) article. It would be something like this:

"Norway is a good place to go skiing. They have a lot of oil-money. Beers are rather expensive there. The capital is Oslo." 

But the point is, that I would share the little I know. And maybe someone else with access to the same wiki knows something else about Norway and will add it. Because they are not obliged to writing a complete, perfect article. That's why Wikis work efficiently for knowledge sharing - and that's the difference to typical websites built with a CMS (in my humble opinion).

But of course Wikis can be based on a CMS like EPiServer. Just wait for it :-)

Tuesday, June 10, 2008

Multiple Templates for a PageType

It looks like a Dev / Partner summit is the perfect birthplace for ideas to grow. Here is yet another idea that grew out of discussions with partners, eMVPs and other Guru's at the summit: It could be cool to have multiple renderings (templates) for a page type. Today several PageType's can share the same template, but it's not possible to specify more than one template to use for a given PageType - a feature which would be very handy when for instance you wanted to make a special set of templates to show your site to mobile users. Or perhaps just special templates for IE or Firefox. Or maybe just a "Printable" set of templates. In any case I think this can be an important building block in making flexible websites.

So, naturally the day after the summit (a bit hungover I must admit) I sat down and began coding. There's several ways to achieve this goal - VPP's being one of them, but to keep it simple I decided to just hook into the UrlRewriting and change the internal url for the pages before they were executed. I ended up with this simple prototype that can change the executing template for a page depending on the User Agent of the client. I'll supply both the source and the compiled versions below - but keep in mind that it's just a prototype and it IS PROVIDED AS IS.

In order to use it, place the assembly in your bin, and add the following to the section-registration of your web.config:

<section name="multiRenderings" type="EPiServer.Research.MultiRenderingSection, MultiRenderingPlugin" allowLocation="true"/>

Then, After the "episerver" section you can add a list of the renderings:

<multiRenderings>
  <renderings>
    <rendering name="IE" userAgent=".*MSIE.*"/>
  </renderings>
</multiRenderings>

This rendering above will try to execute the IE template for userAgents matching the regular expression: ".*MSIE.*" - meaning that all IE browsers will be sent to templates located in the "IE" subfolder (if such templates exist).

On my test site I have the following folder structure:

/      
  Templates    
    MyPage.aspx  
    MyPage2.aspx  
    IE  
      MyPage.aspx

 

When looking at a page that uses "MyPage.aspx" IE will be using the "MyPage.aspx" located in the "IE" folder, but since MyPage2.aspx doesn't exist there, MyPage2.aspx will fall back to the one in "Templates".

This will probably become a lot more elegant as the plugin evolves - but I think it already now might proof useful to some of you, which is why I post it here.

Download from labs.

Sunday, June 8, 2008

Busy Times

A lot of people has been asking me what I'm up to lately - and complaining that my posts aren't as frequent as they used to...
I know it's been way too long since I blogged on this blog. It's not because I have nothing to blog about - in fact every day a new interesting blog-topic springs to mind and I begin writing it...But before I finish it, work or family-life or another idea interferes and break away my concentration.

I just got back last friday from Sweden where I had spend more than a week. First I went to a terrific(!) partner summit and after that I stayed to work at the office with the rest of the Research team. Unfortunately I learned the hard way that I should stay away from local food when traveling to exotic places like Stockholm, so that took a couple of workdays out of my calendar.

At the summit I presented a Wiki built on EPiServer - one of the projects that's been taking a bit of my time lately. Soon I'll do a dedicated post about it - and put it public somehow.
Meanwhile I'm also working on a ton of other stuff - like a new version of EPiDiff, Defining design patterns for EPiServer, LINQ, and a couple of gadgets that I'll reveale in the coming weeks.

Sunday I'm leaving DK again and once again heading for Ukraine, where I'll get to meet our new team in Kiev as well as some developers from a Partner in Kharkov.

Thursday, February 14, 2008

Nightly Fun with 301

WARNING: GEEKY STUFF.

 

Do you ever have difficulty falling asleep at night, because your brain begins to code the moment your tired body hits the bed? Well, I do every once in a while. And then I know that I can either toss and turn all night or sneak downstairs and code for a while - just to get it out of my system.

Last night was one of those nights. This time, though, I decided to make something simple but useful. The idea had been in the back of my head ever since I visited a large client recently who was getting ready to move a big and popular web site in the media industry to EPiServer CMS 5.

Basically this is the classic problem that I'm trying to solve: When moving a web site to a new platform it often happens that the url to the individual pages changes which breaks links, search engine ranks and results in a lot of 404 errors. For instance, with Friendly URLS in EPiServer a page that used to be called "/articles/article124145.html" might now get the friendlier path"/News/New+Website+Launched/". So, my solution to this problem is simply a generic HttpModule that loads a series of old-path / new-path sets from a text-file when the web application is started and then makes a quick check for every request to see if it's actually an old URL being requested. If it is, it'll do the correct thing and send back an HTTP 301 Permanently Moved reply with the new location of the document. That way both global search engines and various caches should get updated and no links will be broken. Simple, but it seems to work - and to my luck it was so easy to code that I still got most of a good nights sleep.

 

    public class RedirectModule : IHttpModule
{
private Dictionary<string, string> map;

public void Init(HttpApplication app)
{
app.BeginRequest += new EventHandler(app_BeginRequest);
map = new Dictionary<string, string>();
//Load from file
StreamReader sr = File.OpenText(ConfigurationManager.AppSettings["UrlMapping"]);
string s = null;
while ((s = sr.ReadLine()) != null)
{
string[] parts = s.Split('|');
if(parts.Length==2) map.Add(parts[0], parts[1]);
}
sr.Close();
}

void app_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (sender as HttpApplication);
if (map.ContainsKey(app.Request.Url.LocalPath))
{
app.Response.Status = "301 Moved Permanently";
app.Response.AddHeader("Location", map[app.Request.Url.LocalPath]);
app.Response.End();
}
}

public void Dispose()
{
}
}



 



As said - it didn't keep me up all night.



In order for it to work the following adjustments needs to go into web.config:



<appSettings>

  <add key="UrlMapping" value="c:\\inetpub\\UrlMapping.txt"/>


</appSettings>



<system.web>

  <httpModules>


    <add name="RedirectModule" type="EPiServer.Research.RedirectModule.RedirectModule,EPiServer.Research.RedirectModule"/>


  </httpModules> 
</system.web>



 



And the mapping file should just be a series of [path]|[new path], one on each line like this:



/oldpath/article.html|/newpath/newarticle.aspx

/oldpath/oldpage|http://www.google.com/?q=oldpage+topic

Wednesday, January 23, 2008

WebResource.axd gives 404

My colleague, Michael Knudsen, has been struggling with a customer & partner for several hours now with an annoying problem on an EPiServer 4.62 site just moved to a production server. Finally, after browsing through half the web and getting valuable feedback from most supporters / developers known to man, a simple solution was discovered.

To save other people the agony he's gone through he persuaded me to post the solution here...

 

Problem symptoms:

When clicking on a button in a webform the following javascript error occurs: Webform_Postbackoptions is undefined. A little simple debugging later it turns out that the page in fact did get a 404 when requesting a web resource (javascript) from the server - which is where the method is defined.

<script src="/WebResource.axd?d=14ZW9Y1So0D_eFk6_pguuw2&amp;t=633359999849186250" type="text/javascript"></script>

If you don't know what webresources does there's a good intro here. This problem had us all stunned for a while - lots of theories going through our heads...."It must be a web.config problem - some handlers are interfering with each others", "Perhaps asp.net isn't properly installed on the server", "But it's working on my machine", "Is this using AJAX?", "Can't we just put the dev. server where it works into production", etc. were some of the thoughts going through our heads as the problem took over our common sense.

 

Solution:

Uncheck this checkbox in IIS:

 

 

un-checked_wildcard

Friday, November 23, 2007

XSLT in EPiServer CMS 5

Personally I'm not a big fan of neither XSLT nor XML. In fact, my feelings around XML is expressed in this quote I heard recently: "XML is like children. They start out cute and small, then they grow..." (I don't remember who said it - if it was YOU, mail me and tell me to credit you for those words of wisdom). In my opinion XSLT's are mainly just good for job-security for XSLT developers - they are about as friendly to read as regular expressions - and terrible to maintain. Nevertheless a lot of people like them due to the way they help separate design from data - and I've already been asked the question "how can I work with XSLT in EPiServer" many times. So, now I thought I better do something about it, so one dark and cold evening I made a web control that hopefully will satisfy all the XSLT magicians out there!

The control will create a XML document representing the current page that has this structure:
    <page>
        <properties>
            <property name="PageLink" type="PageReference" isdynamic="False" isnull="False">3</property>
            ...
        </properties>
        <children>
            <page>
                ...
            </page>
        </children>
    </page>
and then transform that XML using the XSLT you provide.

In order to use the control, you'll need to place the dll in the "bin" folder, and register it on the page you wish to use it on. Then you can put it on the page like this:

<research:XSLT runat="server" id="xslt2" MaxChildDepth=1 IncludeDynamic="true"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns="http://www.w3.org/1999/xhtml"> <xsl:output method="html"/> <xsl:template match="page"> <h1><xsl:value-of select="properties/property[@name='PageName']"/></h1> <ul> <xsl:for-each select="properties/property"> <li><xsl:value-of select="@name"/>: <xsl:value-of select="."/></li> </xsl:for-each> <li> Children: <xsl:apply-templates select="children/page"/> </li> </ul> <br /> </xsl:template> </xsl:stylesheet></research:xslt>





In the above case the XSLT is specified within the controls tag, but you can also reference an external xslt file, by setting the property "TransformationFile" to the url of the XSLT file. Or - if you're feeling mean - you can bind the XSLT contents to a LongString property in EPiServer and let the editors figure out the extended stylesheets - that'll freak them out for sure :-)



By default the control will begin with rendering the XSLT on the current page data - if you want to base it on another page, it can be set up in well-known "PageLink" and "PageLinkProperty" properties.  The "IncludeDynamic" property specifies whether to include dynamic properties or not, and the "AutoHtmlDecode" property specifies if html-tags within properties should be rendered as HTML tags or as text on the page.



Find the control on labs.episerver.com



P.S. If you insist on playing around with XSLT and use this control, I wrote a XPathChecker some time ago that might come in handy.

Friday, November 9, 2007

A Simple Page Import Web Service

In EPiServer CMS 5 there's a couple of very useful Web Services that gives you pretty thorough access to do just about anything you please - at least with regards to adding / searching / modifying pages.

However the Web Services can be pretty complex and at times a green newbie like myself needs a quick & dirty way of importing files from another system into EPiServer without doing too much thinking. In fact, I found myself in exactly that situation recently, when I wanted to import a huge amount of test data I had scavenged on the net (19040 pages to be exact). So I ended up writing a new little web service that takes the following parameters:

  • ParentID - The ID of the page that should be the parent of the page you're adding
  • PageType - The name of the page type to create
  • PageXML - A string of XML, defining the page.The tag-names should match the page properties you want to set, and they should all be wrapped in a <page> </page> tag. So something like "<page><pagename>My Page</pagename><bodyField>This is the body</bodyField></page>"
  • Publish - A boolean parameter that specifies if the page should be published instantly.

The Web method then returns the page-id of the page created, thereby enabling you to build your own page-hierarchy.

In order to make it, I simply created a new standard Web Service in Visual Studio, set the following Using clauses:

using EPiServer;
using EPiServer.DataAccess;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using System.Xml;
using EPiServer.Security;

and added this method to the Web Service class:

[WebMethod]
public int ImportPage(int ParentID, string PageType, string PageXML, bool Publish)
{
    XmlDocument xd = new XmlDocument();
    xd.LoadXml(PageXML);
    PageData pd = DataFactory.Instance.GetDefaultPageData(new PageReference(ParentID), PageType,AccessLevel.NoAccess);
    //Fill in properties
    foreach (XmlNode xn in xd.DocumentElement.ChildNodes)
    {
        if (xn is XmlElement)
        {
            string name = (xn as XmlElement).Name;
            try
            {
                pd[name] = (xn as XmlElement).InnerText;
            }
            catch { }
        }
    }

    PageReference pr=DataFactory.Instance.Save(pd, (Publish)? SaveAction.Publish:SaveAction.Save,AccessLevel.NoAccess);
    return pr.ID;
}

 

So, basically it creates a page with default data, iterates through the 1st level nodes and checks if there is a matching page property. This is a really simple example without any proper error handling, and which only supports string properties. The only thing that's worth noting is how I use the AccessLevel.NoAccess in the Save method and the GetDefaultPageData method, to avoid uncomfortable access checks (since the web service typically runs as an anonymous user). However, make sure always to put the service behind access-control (which can be set up in web.config).

 

And yes, the import of my 19k pages went surprisingly well - and pretty quick too!

Monday, October 22, 2007

How to extend the general Page functionality in EPiServer CMS 5

Still being a newbie in the EPiServer company I learn a lot of new things every day - both about the product and the company.

I've decided to share some of my discoveries here - perhaps they help other EPiServer newbies out there :-)

Today I came across quite a useful, but not-so-well-documented feature in EPiServer CMS 5: The ability to extend the general functionality of your Pages. So, if for instance you want to add a piece of code that should be executed whenever a page is shown, and which can affect that page, but don't feel like inheriting the TemplatePage type and letting all your pages inherit from your custom type, there is actually quite a neat way of doing it.

The trick is the PagePlugIn attribute. You can create a class, put the PagePlugIn attribute (from the EPiServer.PlugIn namespace) and add static method with the signature void Initialize(int) and from that method setup an event handler to handle the EPiServer.PageBase.PageSetup event.

Here's an example on how you can use this functionality to add an extra menu item to the context menu:





[PagePlugIn]
public class MyPagePlugin
{

public static void Initialize(int bitflags)
{
EPiServer.PageBase.PageSetup += new EPiServer.PageSetupEventHandler(PageBase_PageSetup);
}

static void PageBase_PageSetup(EPiServer.PageBase sender, EPiServer.PageSetupEventArgs e)
{
sender.ClientScript.RegisterClientScriptInclude("OnScript", "MyScript.js");
sender.PreRender += new EventHandler(sender_PreRender);
}

static void sender_PreRender(object sender, EventArgs e)
{
(sender as EPiServer.PageBase).ContextMenu.Menu.Add("MyItem", EPiServer.Security.AccessLevel.Edit, new EPiServer.RightClickMenuItem("My Script", "MyScript()", "MyScriptSubMenu"));
}

}

Monday, October 8, 2007

Off to Stockholm

After a terrific first week at EPiServer Denmark, I'm off for a 3-day introduction tour to the swedish HQ.
In the first week I accomplished most of what I set out to do: I got my laptop up and running, with a decent dev. environment, almost learned my way around Vista (still don't know if I like it) and got started on a couple of really interesting projects.

I've also started an episerver-based blog on the Research site, r.ep.se - but don't worry, I plan to crosspost a lot so you shouldn't be missing out on anything here.
So far EPiServer seems to be both a great product and a really nice company - I certainly can't complain about the way I've been received so far.

So, now all thats left to do is to look forward to some of the famous swedish cuisine in the next 3 days to come...

Monday, October 1, 2007

First Day on the new Job

Today was my first day at the new job at EPiServer, and I must say that the future is looking bright!
A lot of new cool hardware had arrived for me (in fact, I'm posting this from my new Lenovo T61p laptop) and - yes, I've taked the step to Vista (finally).
So, naturally I spend a lot of day unpacking hardware, installing and learning my way around Vista (only made it crash twice).
I also had a chance to discover what some of the first tasks for me will be, after I have my dev-environment set up and memorized all of the EPiServer API by heart. It looks like I'll get to play around a little with building a wiki for EPiServer (there seems to be a demand) and I also get to finish a little project that I already started some days ago, making a Mail2EPiPages job. I'll try to post a little more - but don't be surprised if it's all EPiServer specific. Although I'll try to cross-post a lot of my posting will probably be on a blog on the EPiServer Research site.

I owe a big thanks to the great welcome I've received so far at EPiServer - and EPiServer Denmark (THANKS Michael!). I really have a good feeling about my future in this company...

Monday, September 24, 2007

EPiServer Code: Send a warning email when a page is about to expire

As you might imagine I find it difficult to keep my hands of the brand new v.5. So naturally I've been searching out excuses to try out coding some small samples against the API.
Here's a feature that I've heard requested from several intranet customers already - An automatic email that informs the owner of a page that it's about to expire.
"What a great idea" I thought first time I heard it - One of the major problems with most intranet is outdated information so I can easily imagine companies having a policy that all pages on their intranet should have an expiration date - and I can just as easily imagine the need for owners to change that expiration date, if the information is still relevant hence producing the need for a warning email.
First off I could see several approaches to making this in EPiServer:
  1. Hook into the right DataFactory event from the global.asax and send a mail whenever a page is expiring
  2. Use the v5 support for workflow foundation and make a workflow that performs a SendEmail activity when a page is moved to the archive
  3. Set up a scheduled task to check for pages about to expire
Although I found option 2 very encharming due to the use of workflows, I decided to make an implementation of option 3 - since this was the only approach that would send out a warning email before the page actually expired (and any damage was done).

I made a new C# Code library project, added references to the relevant EPiServer dlls (and log4net to enable logging) and wrote this code:



using System;
using System.Collections.Generic;
using System.Text;
using EPiServer.PlugIn;
using EPiServer;
using EPiServer.Core;
using EPiServer.Filters;
using EPiServer.Security;
using EPiServer.Personalization;
using EPiServer.Configuration;
using System.Net.Mail;

namespace Allan.EPiModules
{
[ScheduledPlugIn(DisplayName = "Page Expiry Warning")]
public class ExpiryWarningJob
{
private static log4net.ILog _log;

static ExpiryWarningJob()
{
_log = log4net.LogManager.GetLogger(typeof(ExpiryWarningJob));
}

public static string Execute(){
int num = 0;
//Find pages that will expire in a day
PropertyCriteria criteria = new PropertyCriteria();
criteria.Name = "PageStopPublish";
criteria.Value = DateTime.Now.AddDays(1).ToString();
criteria.Type = PropertyDataType.Date;
criteria.Required = true;
criteria.Condition = CompareCondition.LessThan;
//...but hasn't already expired
PropertyCriteria criteria2 = new PropertyCriteria();
criteria2.Name = "PageStopPublish";
criteria2.Value = DateTime.Now.ToString();
criteria2.Type = PropertyDataType.Date;
criteria2.Required = true;
criteria2.Condition = CompareCondition.GreaterThan;
PropertyCriteriaCollection criterias = new PropertyCriteriaCollection();
criterias.Add(criteria);
criterias.Add(criteria2);
foreach (PageData data in DataFactory.Instance.FindPagesWithCriteria(
PageReference.RootPage, criterias,
null, LanguageSelector.MasterLanguage(), AccessLevel.NoAccess)
)
{
SendMail(data);
num++;

}
return string.Format("{0} expiry emails sent", num.ToString());

}


private static void SendMail(PageData p)
{
//Identify user profile.
//Consider using the ChangedBy instead of CreatedBy.
EPiServerProfile esp = EPiServerProfile.Get(p.CreatedBy);
if (esp.Email != null)
{
try
{
//Build a new mail message
MailMessage message = new MailMessage("expire@" + Settings.Instance.SiteUrl.Host, esp.Email);
message.Subject = "Page \"" + p.PageName + "\" is about to expire";
message.Headers.Add("X-Mailer", "EPiServer CMS");
message.Headers.Add("Content-Base", Settings.Instance.SiteUrl.GetLeftPart(UriPartial.Authority));
message.Body = "The page <A href=\""
+ Settings.Instance.SiteUrl.GetLeftPart(UriPartial.Authority)
+ p.StaticLinkURL + "\">"
+ p.PageName
+ "</A> will expire on "
+ p.StopPublish.ToShortDateString();
message.IsBodyHtml = true;
message.BodyEncoding = Encoding.UTF8;
SmtpClient smtp = new SmtpClient();
//Make sure the web.config sets up the SMTP Client.
smtp.Send(message);
_log.Info("Expiry warning sent to: " + esp.Email);
}
catch (Exception e)
{
_log.Error("Failed to send expiry warning", e);
}
}
else _log.Warn("Unable to send expiry warning to " +
esp.DisplayName +
" - no known email address");
}
}
}

The dll should be placed in the EPiServers "bin" folder and then it will automatically be loaded. The ScheduledPlugin attribute will make it appear as a scheduled task in Admin mode. Here you should probably set it to run once a day - perhaps in the early hours of the morning will be best.
You also need to make sure the web.config is setup to the SMTP server.

The code is a pretty simple sample that will find the pages that are about to expire (the following day) and then send a mail to the creator of each page that it's about to expire.

The sample was made in less than a day and of course it still could use a lot of work to be really nice. Ideas for improvements:
  • Group expiration mails so that each user won't be bombarded with several mails every day
  • Consider how long time before people should be warned that the pages are about to expire - is 1 day time enough?
  • Consider if it's really the creator that should get the mail - perhaps the last person to have updated the page would be the right one?
  • Build functionality together with tasks - so instead of emails a task to check the page should be created.
Enjoy!

New Job!

Just a quick personal update: I've decided to join the great team at EPiServer, starting october 1st as a Technical Architect. I'll still be based in Copenhagen, Denmark - but my primary work-area will still be within development (which for the most part is in Stockholm) so I guess I'll once again get to try working virtually with people all over the world.
I'm looking very much forward to joining the EPiServer family and I hope that I'll be able to contribute to make the EPiServer CMS an even better product (although it's already quite good).

...And just to answer an obvious question: Yes, this means that there might be more CMS and EPiServer related posts on my blog in the future - but I'll still try to find time between changing my sons diapers and developing CMS features to post some more unrelated crazy code :-)

Friday, August 31, 2007

PRSS = Post Release Stress Syndrome

It's been a while since I last blogged, and a lot have happened in the time.
Mostly I've been busy with the post-release of Maximilian 1.0 (= my son). It's amazing how tricky it is to code and blog, with such a cute kid to distract you and a lot of diapers to change...

Now, however, we're slowing finding a routine in our daily lifes and I'll try to start blogging again - but bear with me if I don't post daily like I used to.

I have a ton of unfinished coding and blogging projects in the pipeline that I'll try to finish off while at the same time I'll try to keep posting my comments when I see new cool developments in my spheres...Like today when Mats, you pointed me to the fact that EPiServer 5 RC4 just has been released. I already have a download in progress and I can't wait to see what changes it has brought since RC2.

Friday, July 6, 2007

EPiServer 5 CMS - First impressions

A couple of weeks ago I wanted to check out how the new EPiServer 5 looked, so I downloaded a free trial version of the RC2.
It comes in two flavors. There's the traditional installer that installs the Manager which allows you to setup new EPiServer websites with a default look & feel, but on top of that there's also a new Visual Studio integration available that I instantly knew I just had to try out.

The install itself was very (!) easy and without any problems or hickups I had a lot of new features in my visual studio.
For instance I now had the possibility of creating a new EPiServer Project which I instantly did.
This template created blank episerver website, db, etc. for me ready to use.
It's really clear to see that with this new release the clever guys at EPiServer has been focussing a lot on improving the quality of life for all the developers out there who use it as an every day tool to make websites.
At the same EPiServer is now even tighter coupled with the newest Microsoft technologies, basing their CMS on standard ASP.NET 2.0 things like Master pages and ASP.NET User/Role configuration. They've also done a tremendous job of integrationg Workflow Foundation into the core functionality - and to this date this seems like one of the best usages of WWF I've seen so far.

Seen from a developer perspective the new SDK makes me think of EPiServer as a huge toolbox that gives me a lot of tools to efficiently create cool websites and webfunctionality in a standard ASP.NET way, while taking care of a lot of the tedious details. But from an Editor / Administrator perspective you still get the well-known intuitive webbased interface for administrering and editing the website. Cool.


The editor and administrator interface hasn't changed all that much since last version and the entrypoint is still the "famous" right-click menu for logged-in editors. It seems to me like the Editor interface hasn't gotten all that much work done except for a paint-job and perhaps some improved versioning/comparison features (however I could be mistaking, having never been a real-life editor :-) ). Thats okay, though. Rome wasn't build in a day and I certainly prefer the improved SDK and architectural changes.
Yes, I am the kind of guy who cares more about whats under the hood of my car, than the color, shape and sexiness of it's exterior. However it still wouldn't hurt to give a bit of attention to improve the (already good) usability for editors and administrators in a future version. Perhaps AJAX is a good approach here.

While I'm at it, here's another few things for my wishlist for future versions: WCF support for easier data / functionality access and a couple of nice fully-featured demo-sites / templates for the SDK. It could be nice to a couple of ready-to-go samples as VS Templates.

All-in-all I'm very impressed with the RC2 version of EPiServer 5 and I can't wait to play around with it some more. Don't be surprised if a couple of modules start appearing on this blog for free download in the near future. EPiServer continues to be a powerful workhorse in the CMS world, not as flashy and shiny as some competitors but intuitive, strong and flexible.

Thursday, June 21, 2007

EPiGirl leads the way

I just came across Rachel Goldthorpes newly started Blog on EPiServer development.
She definetly seems to be off to a good start with her post on getting started with EPiServer 5 CMS - it looks very helpful and I'll definetly keep it in mind when I get the chance to try out the new RC.
Welcome to the blogging sphere EPiGirl and keep up the good work!