Thursday, December 8, 2011

FusionCharts (v3.2.2) javascript bug in IE 8

A customer I’m working with requires data generated charts on their EPiServer website, and for that purpose I’ve implemented FusionCharts. By default FusionCharts render Flash charts with a javascript fallback, or you can simply choose to always render javascript charts if you’re not a fan of Flash.

The FusionCharts documentation is one of the best documentations I’ve ever seen, a pleasure to read, and the installation takes two minutes. Seems like a blast doesn’t it!

I thought so until the front-end developer for the project I’m working on came over to my desk and informed me that the charts did not render in IE 8. They worked fine in IE 7 and IE 9, but not IE 8. Say what? I checked it out and saw that FusionCharts.js gave me a “Invalid argument” error on line 76. Since Google is my friend, I googled the problem and found A LOT of other developers on the FusionCharts forum running into the same problem, but the only answer from FusionCharts was that their developers were working on it. They’ve been working on it for over a month and could not say when the bug would be fixed.

The project is going live in about two weeks, so I don’t have time to wait for other developers to fix their bugs. I tried downgrading to the previous version of FusionCharts, but that caused me some other problems, so I went back to v3.2.2. I googled some more and found a FusionCharts service release that was newer than the version I am using, but the javascript error seemed to be living happily ever after.

So what solved my problems?

I have several charts on one page, and therefore each chart needs its separate ID. Being a developer, I set the ID to be a number (big mistake). Apparently the ID can contain numbers, but it cannot begin with a number, so ID=Chart1 is fine, but ID=1Chart will give you a javascript error in IE 8.

Hopefully they’ll fix this in the next version, or at least add a note of it in their (almost) perfect documentation.

Friday, October 28, 2011

Epinova.CRMFramework version 1 has been released!

For the last couple of years I’ve worked with several customers who wanted to integrate their websites with Microsoft Dynamics CRM 4.0. There are several frameworks available for doing just that, but I never found one that I was 100% satisfied with so I began playing with the thought of creating my own framework.

Then a year ago, I found myself having a couple of weeks of free time between two jobs and I decided to give it a go. I sat in a café with my laptop for the next couple of weeks, and after a lot of coding and coffee drinking I released the alpha version of Epinova.CRMFramework.

So what was so wrong with the other frameworks out there? The main problem was that none of them were as generic as I needed them to be. You could only work with standard CRM entities, and as soon as you needed a custom entity you would have to make a hack in order to do this. The ones that supported both standard and custom entities were not able to retrieve many-to-many relationships or required extreme amounts of configuration in order to do this.

I set myself a list of goals, the framework would be

- generic and developer friendly
- able to do all necessary operations (create, read, update, delete) on all types of entities (standard and custom)
- able to retrieve one-to-one, one-to-many and many-to-many relationships between entities.
- easy to configure, the amount of configuration should be kept at a minumum.

A year later, the framework has been thoroughly tested and I have fulfilled these goals. It has been used by a large customer for half a year and they haven’t run into any problems so far. I plan on keeping it that way!

You can download Epinova.CRMFramework and read the documentation on codeplex.

Now that version 1 is out, it’s time to plan the next version. I’ve received a lot of questions regarding support for Microsoft Dynamics 2011, and this is my main goal for version 2. I also know that a lot of people want a membership provider to be included in the framework, but I’ll have to give this some thought.

I’ll keep you posted when I’ve thought my plans through! For now, enjoy my framework and let me know if you have any questions :) I’m getting myself a coffee to celebrate!

Thursday, September 15, 2011

EPiServer vNext Falcon Seminar – My thoughts

I’ve been spending the last couple of days in the beautiful city of Stockholm in order to attend the EPiServer vNext Falcon Seminar and meet up with the Swedish developers we see every day at Twitter and EPiServer World.

The Swedish hospitality has been great, in the form of lunches and drinks and also borrowing a work desk at the Nansen office. Thank you very much, Martin Söderlund and Leif Boström!

So then, EPiServer vNext Falcon! There were three key points in the presentations, I will go through each one and state my thoughts. EPiServer made it very clear that this is all work in progress, and things might (and probably will to some extent) change. So to you reading this blog post two years from now: These are my private opinions based on how I interpreted what was said during the presentations.

Add-Ons

The Add-On system is a piece of functionality that I think will be loved by editors and potentially frowned upon by developers if EPiServer don’t play their cards right.

The Add-On system can be compared to an “App Store” where editors can install Add-Ons to their website without involving any developers. The Add-Ons will be available through a NuGet feed and will probably have to go through an approval process in order to become available.

There are quite a few interesting challenges when it comes to this, and these possible challenges were made clear in the Q&A after the presentation:

-  How will EPiServer deal with Add-Ons and load-balancing?
-  How will EPiServer ensure that a site doesn’t break when an editor installs an Add-On?
-  Will contributing developers be compensated for creating an Add-On?

In addition to the Add-On system, there was a short presentation on Localiation. EPiServer announced that their language files will be included as embedded resources in vNext. I quite like this, as it removes EPiServers files from the developers files, and I can’t remember ever having to edit one of the EPiServer language files.

Typed pages

This is a huge one!! We’re all familiar with PageTypeBuilder, every developers dream and every editors nightmare, and EPiServer has come to the terms that they need to include typed pages in order to make us all just a little bit happier.

One of the things I found quite interesting is the concept of Blocks (another term for property groups). Grouping of properties into Blocks (for example an image, and alternative text and a link) will diminish the need for custom properties. This in connection with allowing complex property types such as Lists or Dictionaries will in the long run mean that we won’t need custom properties at all. Oh joy!

EPiServer also suggested that properties defined in code should be made hidden (or not editable) for editors. One of the issues we’ve had with PageTypeBuilder is when a property’s attribute (such as SortIndex) is set in code, and the editor changes this attribute, the change made by the editor will be overridden when a new deploy is done. Hiding properties defined in code from the editors will (hopefully) solve this issue.

MVC Support

This is another case that deserves a large Woho! I’ve been drooling over ASP.NET MVC for quite a while, but creating Gadgets doesn’t quite dry up the drool. We were shown how MVC Routing will be implemented to work with EPiServer friendly URLs. The fact that a site can contain both web forms and MVC is even better.

There are a couple of downsides for the editors though. On-page-edit won’t work with MVC and neither will the right click menu.

Disappointments

I was hoping I wouldn’t need this section of the blog post, but sadly I do. I’m very disappointed that EPiServer isn’t giving the File Manager any love. It’s a pain for the editors to work with, and it’s quite outdated compared to how everyone have gotten used to managing files.

Unconfirmed rumors and possible bogus

- Will edit mode “disappear” in the long run to be replaced with an on-page-edit like UI with Widgets?

- As a result of the previous point, will on-page-edit disappear?

- Will edit and admin mode be rewritten to MVC?

- Are the developers at EPiServer superheroes who will be able to deliver all of this in Q1?

Friday, August 26, 2011

Authenticate a Web Service in EPiServer using a SQL Server membership account

I dumped into some trouble today, trying to authenticate a web service in EPiServer using a SQL Server membership account. You would think following the steps in the Web Services tech note would be enough. However, the tech note is missing some important information. Therefore I thought I’d create a small overview myself.

Assumptions:

1) You have created a web service in the WebServices folder of your EPiServer website. Or you are trying to authenticate one of the build-in web services using a SQL Server membership account.

2) You have configured EPiServer to Enable Basic Authentication by adding the BasicAuthentication http module in the <system.web><httpModules> section (for IIS 6) or <system.webserver><modules> section (for IIS 7) of your web.config file:

<system.webServer>
<modules ...>
<add name="BasicAuthentication" type="EPiServer.Security.BasicAuthentication, EPiServer" />
<!-- Other modules -->
</modules>
</system.webServer>

3) You have a <location path=”WebServices”> section in your web.config file:

<location path="WebServices">
<episerver.basicAuthentication sendBasicChallenge="true" basicRealm="" />
<system.web>
<httpRuntime maxRequestLength="1000000" />
<authorization>
<allow roles="Administrators, WebServices" />
<deny users="*" />
</authorization>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<clear />
<add name="webresources" path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" />
<add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" modules="ManagedPipelineHandler" scriptProcessor="" resourceType="Unspecified" requireAccess="Script" allowPathInfo="false" preCondition="integratedMode" responseBufferLimit="4194304" />
<add name="wildcard" path="*" verb="*" type="EPiServer.Web.StaticFileHandler, EPiServer" />
</handlers>
</system.webServer>
</location>

4) You have created a group called WebServices in EPiServer admin mode, and have added a SQL membership user to this group. This is the user you want to authenticate your web service with.

5) You have disabled integrated authentication and basic authentication in IIS.

So, what’s the problem?

If you test your web service in a browser (http://localhost/WebServices/MyWebService.asmx), you should get a windows login window instead of the http://localhost/util/login.aspx page. Awesome! This means that you’ve configured everything correctly.

Now if you’re unlucky like me, you will get an unauthorized message when trying to logon using the web service user you created in step 4. So you go over your configuration again and again and again. But everything looks correct…

So what the tech note fails to mention is the fact that your web service user has to be added to the list of web service users under “Permissions to functions” in Admin mode.

So, add the user and voilá!

Wednesday, June 15, 2011

NDC2011 Aftermath

IMAG0257

Last week I attended the Norwegian Developers Conference for the first time during my career, and I must say I was impressed!

Before the conference my expectations to learn something new, fuel up on motivation, meet old friends and make new friends. Looking back, I can with a 100% certainty say that these expectations were met.

Top sessions (of the ones I was able to make it to):

1. “ASP.NET MVC 3, EF Code First, NuGet, and IIS Express” by Scott Guthrie

This session gave a great overview ASP.NET MVC 3, EF Code First, NuGet and IISExpress which I at this point hadn’t had the chance to try out properly in a project. Needless to say, Scott Guthrie is amazing and so was his session! I got high on ASP.NET MVC 3 after this session, and I’m hoping I’ll have the chance to try it out more in a real life project in near future.

2. “Because You Suck at Design Patterns” by Gary Short

Gary Short gave a great overview of the mostly used design patterns and how most of us use them wrong. One of his most important messages was to know your platform. A design pattern in C++ might not be the same as in C#. This session confirmed to me that I, in fact, do suck at design patterns. So now I’m up for some relearning :)

3. “Functional Programming in C#” by Oliver Sturm

I had a Scheme course in University that I absolutely hated, so I thought I’d try to look into functional programming with an open mind when attending this session. The session was interesting, although at some points I was happy I’d brought coffee. It was very interesting to see the effect of functional programming in C#, but I don’t see myself becoming a huge fan of functional programming any time soon.

4. “Progressive EPiServer Development” by Joel Abrahamsson

Joel Abrahamsson took us though his thoughts on flaws in EPiServer and frameworks created in order to avoid these flaws. Most of it, I’d heard before, but I found a few things quite interesting. For example the future plans of PageTypeBuilder which I’m very much looking forward to!

5. “Continuous Deployment for ASP.NET” by Ben Hall

This session was just above average, but thanks to one sentence said during the presentation, this session was able to make it to my “top sessions” list. The sentence was “A deploy should be a non-event”. In most projects I’ve worked on so far, a deploy is THE greatest event, and the nerves and expectations are accordingly. This sentence made me decide to view depoys in a different way.

The social part

It was great meeting previous colleagues, old classmates and old friends at the conference!

Most of all, it was great to make new acquaintances :) As quite a lot of Swedish EPiServer developers were attending the conference, I decided to set up a dinner so we all could meet up. At first I was planning a small dinner in a restaurant, but as I realized that the number of Swedes coming to town was quite large, I decided to arrange the dinner at the Epinova office instead.

Close to 35 developers showed up, enjoying tapas, drinks and each others company. Quite a success, if I can say so myself! Unfortunately we had such a good time that we almost forgot to take any pictures, but here are the few (appropriate) I took:

IMAG0258

IMAG0260

IMAG0261

IMAG0262

IMAG0265

IMAG0266

IMAG0267

IMAG0271

 

 

 

I’m looking forward to NDC2012! :)

Monday, February 28, 2011

Remove old versions job in EPiServer CMS 6

At the moment I’m creating a new EPiServer site for a customer. They have an existing CMS 6 site, and we need to migrate some content from the existing site to the new one.

The existing site was upgraded from EPiServer 4 to CMS 6, and it has never had a max value set for the number of page versions allowed per page. This means that for some pages there were 500 different page version.

So we definitely needed to do some cleaning before migrating the content. I found the Remove old versions job, but this is only for EPiServer 4.

I’ve rewritten the job so that it works on CMS 6. Mind you that I've not written this piece of code, I’ve only edited it to work for CMS 6. Unfortunately, I don’t know who wrote this code but all credit should be given to him/her!

Here’s the code:

[ScheduledPlugIn(DisplayName = "Clear old version job")]

public class RemoveOldPageVersionsJob

{

  private static RemoveOldVersionsDb _removeOldVersionsDb;

  private static int _maxVersions;

  private static int _numberOfPagesRun;

 

  /// <summary>

  /// Start job

  /// </summary>

  public static string Execute()

  {

    _numberOfPagesRun = 0;

    _removeOldVersionsDb = new RemoveOldVersionsDb();

 

    _maxVersions = EPiServer.Configuration.Settings.Instance.UIMaxVersions;

    PageData rootPage = DataFactory.Instance.GetPage(PageReference.StartPage);

    FixBranch(rootPage);

 

    return "Removed all old versions except " + _maxVersions + " for all pages (" + _numberOfPagesRun + ") as the following user: " + HttpContext.Current.User.Identity.Name;

  }

 

  private static void FixBranch(PageData page)

  {

    _numberOfPagesRun++;

    _removeOldVersionsDb.RemoveVersions(page.PageLink.ID, _maxVersions);

    PageDataCollection children = DataFactory.Instance.GetChildren(page.PageLink);

    foreach (PageData child in children)

      FixBranch(child);

    }

  }

 

public class RemoveOldVersionsDb : DataAccessBase

{

  public void RemoveVersions(int pageId, int maxVersions)

  {

    try

    {

      OpenConnection();

 

      IDbCommand cmd = CreateCommand("editDeleteObsoletePageVersions");

      cmd.Parameters.Add(CreateParameter("PageID", pageId));

      cmd.Parameters.Add(CreateParameter("MaxVersions", maxVersions));

 

      cmd.ExecuteNonQuery();

    }

    finally

    {

      CloseConnection();

    }

  }

}

Thursday, January 27, 2011

Page preview not visible in EPiServer edit mode

After upgrading a site to EPiServer CMS 6, I tested the site and everything worked as it should. A couple of hours later I got an email from the customer saying that the page preview was not visible in edit mode. Everything else in edit mode was visible, except for the page preview.

I couldn’t understand this as I had tested everything, but after some investigation I realized that this only happened if you were not accessing the site from the server. And it only occurred in IE (in Firefox the page preview was working, but some of the buttons were missing).

It turns out I made a silly mistake, I forgot to check that the VPP folder paths were correct in the episerver.config file. Still, a missing page preview was a quite confusing indication of this. So if the same thing happens to you, you’ll now know what you can check :)

So the moral of the story is:

- Make sure your VPP folder paths are correct after an upgrade!
- Don’t just test the site from the server it’s on, test it from the outside as well….
- Don’t make silly mistakes like this ;)

Wednesday, January 19, 2011

Dynamic error pages in EPiServer with static fallback

Recently, I got a request from a customer wanting a dynamic 404 error page. I told them I’d prefer them to stick to the static 404 error page they already had, as dynamic error pages can cause a lot of trouble. It’s recommended that a 404 page should not read from the EPiServer database or retrieve any graphics. This is due to the fact that if your 404 error page is an EPiServer page and someone deletes it on accident, you can end up in an infinite 404 loop. And we don’t want that, do we?

So what would be perfect was a dynamic error page with a static fallback! I started looking around at the plenty blog posts out there by other EPiServer developers and found some quite clever solutions. However, none of them worked quite the way I wanted it to. So then I did what I always do: Tweet about it!

The response was brilliant! A lot of people recommended the 404Handler on EPiCode, but this reads from the lang files and the customer wanted to edit the 404 page from edit mode. So I ruled that one out. Another solution, by Steve Celius, was to use the 404Handler on EPiCode and create a page that saves content to a lang file. This is in fact a good solution, but unfortunately it was presented to me too late. I had already implemented the solution explained below.

The savior of the day was Jens Altbäck, a system architect as SPV. He sent me some code he’d used in a previous project. I’ve simplified the code a bit and made a few modifications, but remember that the great mind behind it is Jens, not me. I’m just the one who’s obsessed with the “sharing is caring” mentality and therefore have an urge to blog about it :)

The idea of it all is simple! You need four things:

- ErrorPageType (optional, but recommended): A pagetype with whatever properties you need, for example Heading and ErrorMessage. You could leave this pagetype out and use one of your existing pagetypes instead, but in order to restrict the editors it’s recommended that you create this pagetype so that you can determine where in the pagetree the page can be created and who should have access to creating the error pages. As you can create this pagetype in whatever way you want, I will not show you how to do this. In the example below, however, I’ve assumed that the pagetype has two properties: Heading and MainBody.

- ErrorHandler.aspx: Determines how the error page should be displayed. Mind that the ErrorHandler.aspx is not used for any pagetypes!

- ErrorHandler.aspx.cs: Gets and sets the correct StatusCode for the Response, determines if an error page exists for the current error. If it exists, the ErrorHandler sets its currentpage to the errorpage, or else it redirects to the static error page.

- error.htm: Static error page.

Here’s a step by step guide to how this all should be put together:

1) Create your ErrorPageType

Create your ErrorPageType with the appropriate properties. Create a page of this pagetype called ‘Page not found’ somewhere in the pagetree of your EPiServer site.

2) Add a property to your startpage

Add a property to the startpage of your site. This property should be called ‘HTTPStatusCode4xxPage’ and be of type Page. Point this property to the page you created in step 1.

3) Create the error.htm static error page.

Create a static html error page called error.htm and put it in the root folder of your website. If the dynamic error page is missing, the user will be directed to this static error page instead.

4) Create the ErrorHandler

The codebehind should look like this:

public partial class ErrorHandler : Templates.Base.TemplateBase

{

  private int statusCode = 0;

  private PageData errorPage = null;

 

  protected void Page_Init(object sender, EventArgs e)

  {

    GetStatusCode();

    SetStatusCode();

    SetErrorPage();

    SetCurrentPage();

    RedirectToDefaultErrorPage();

  }

 

  private void GetStatusCode()

  {

    // More to come...

  }

 

  private void SetStatusCode()

  {

    // More to come...

  }

 

  private void SetErrorPage()

  {

    // More to come...

  }

 

  private PageData GetHTTPStatusCodePage(string errorCodeProperty)

  {

    // More to come...

  }

 

  private void SetCurrentPage()

  {

    // More to come...

  }

 

  private void RedirectToDefaultErrorPage()

  {

    // More to come...

  }

}

Let’s start by looking at the two first methods: GetStatusCode() and SetStatusCode(). In order for the ErrorHandler to work properly, we need to set Respone.StatusCode to the correct status code:

/// <summary>

/// Get the HTTP error status code from the querystring

/// </summary>

private void GetStatusCode()

{

  string[] requestQueryStrings = Request.QueryString[0].Split(';');

 

  if (requestQueryStrings.Length > 0)

  {

    int code = 0;

    if (int.TryParse(requestQueryStrings[0], out code))

    {

      statusCode = code;

    }

  }

}

 

/// <summary>

/// Set the status code of the response

/// </summary>

private void SetStatusCode()

{

  if (statusCode != 0)

  {

    Response.ClearHeaders();

    Response.StatusCode = statusCode;

  }

}

The next methods are the SetErrorPage() and the GetHTTPStatusCodePage() methods. SetErrorPage() uses GetHTTPStatusCodePage() to determine if an error page exists. If it does, the private PageData object  called errorpage is set. Notice that you can extend the SetErrorPage() method to handle other errors than HTTP 404 as well as long as you create a property for it on the startpage and add it to the web.config (see step 5).

private void SetErrorPage()

{

  switch (statusCode)

  {

    case 404:

      PageData current4xxErrorPage = GetHTTPStatusCodePage("HTTPStatusCode4xxPage");

      if (current4xxErrorPage != null)

      {

        errorPage = current4xxErrorPage;

      }

      break;

    default:

      break;

  }

}

 

/// <summary>

/// Get the page set by the errorPagePropertyName on the startpage

/// </summary>

/// <param name="errorCodeProperty">Name of the startpages property</param>

/// <returns>The page set by the errorPagePropertyName</returns>

private PageData GetHTTPStatusCodePage(string errorPagePropertyName)

{

  if (PageReference.StartPage == PageReference.EmptyReference)

    return null;

 

  PageData startPage = GetPage(PageReference.StartPage);

  if (startPage != null)

  {

    PageReference errorPageRef = startPage[errorPagePropertyName] as PageReference;

    if (!PageReference.IsNullOrEmpty(errorPageRef))

      return GetPage(errorPageRef);

    }

    return null;

}

Last, but not least: Add the SetCurrentPage() and RedirectToDefaultErrorPage() methods. The SetCurrentPage() method is in my opinion the piece of code that makes this all so brilliant! If we were to redirect the user to the error page instead of setting current page and the user refreshed the page, the HTTP request done would be towards the error page, not the original page the user requested. Setting the currentpage ensures that is the user refreshes the page, the request done is towards the original page:

private void SetCurrentPage()

{

  if (errorPage != null)

  {

    CurrentMasterPage.CurrentPage = errorPage;

  }

}

 

private void RedirectToDefaultErrorPage()

{

  if (errorPage == null)

  {

    Response.Redirect("~/error.htm", true);

  }

}

And now the ErrorHandler.aspx. In this example I’ve assumed that the ErrorPageType contains two properties: Heading and ErrorMessage. So in ErrorHandler.aspx I want to display these two properties:

<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/Templates/MasterPages/MasterPage.master" CodeBehind="ErrorHandler.aspx.cs" Inherits="ActaWeb.ErrorHandler" %>

 

<asp:Content ID="Content1" ContentPlaceHolderID="BodyRegion" runat="server">

  <EPiServer:Property PropertyName="Heading" DisplayMissingMessage="false" EnableViewState="false" runat="server" />

  <EPiServer:Property PropertyName="ErrorMessage" DisplayMissingMessage="false" EnableViewState="false" runat="server" />

</asp:Content>

You might be wondering why this code is required, will it ever be displayed to the user? Oh yes, it will! As we’ve set currentpage in the codebehind instead of redirecting to the errorpage, this is in fact the code shown to the user. So it doesn’t matter how the ErrorPageType looks, as that will never be shown to anyone visiting the site, it will only be viewed by the editors in edit mode.

5) Edit the <httperrors> section of your web.config file

The <httperrors> section of the web.config should now look like this:

<httpErrors errorMode="Custom">

  <clear />

  <error statusCode="404" prefixLanguageFilePath="" path="/ErrorHandler.aspx" responseMode="ExecuteURL" />

</httpErrors>

And that it!

I’d like to thank Jens Altbäck for showing me this great solution and letting me blog about it. If you’re wondering who this brilliant guy is, you should follow him on Twitter: @jensaltb