Showing posts with label CrossPost. Show all posts
Showing posts with label CrossPost. Show all posts

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.

Thursday, September 3, 2009

HTTP Error 500.19 – Internal Server Error

A couple of times I have now run into this wonderful error after setting up a new EPiServer CMS site on a newly installed machine. However, I don’t think it’s specific to EPiServer CMS – but can occur in any asp.net application. The error message looks like this:

The requested page cannot be accessed because the related configuration data for the page is invalid.

As with many other microsoft errors, this is completely misleading (unless you’ve been messing up your configuration data – but this is a newly installed site).

The error message tries to clarify itself further:

Module
IIS Web Core

Notification
BeginRequest

Handler
Not yet determined

Error Code
0x80070021

Config Error
This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".

Config File
\\?\C:\EPiServer\Sites\MyEPiServerSite3\web.config

 

By now, you are probably half way into your web.config, and trying to remember where that mystical machine.config is located. You might even have started to go through all directories on your machine in the search for another web.config thats somehome conflicting. Stop looking. It’s not conflicting. And relax – you didn’t do anything wrong…yet.

One of 2 things have likely happened:

1) IIS was installed after ASP.NET, and it’s not really sure what to do with ASP.NET code. Solution: In a command prompt run aspnet_regiis. It’s typically found in “%windows%\Microsoft.Net\Framework\v2.0.50727\aspnet_regiis –i”. Note that you need to run it as Administrator on Vista and Windows 7. In fact, running this can be a cure for many initial web server errors on newly installed asp.net applications.

2) You are running Windows 7 or Windows Server 2008 and you selected the default install of IIS7.5. For reasons known only to Microsoft, they decided that ASP.NET shouldn’t be included in a default installation. My personal theory is that the guy who made that wise call is probably the same guy who decided to remove the ability to drag files onto a command-prompt in Vista. And before that was the mastermind behind the “Copy File” feature in any earlier version of Windows. But I digress :-) Solution in this case is easy – Open Control Panel | Programs | Turn Windows Features on and off, find IIS and enable ASP.NET:

image

Hit “Ok”, wait for half an hour and then see your web application spring to life. Enjoy!

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.

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.

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"));
}

}