IE Date Parsing Doesn’t Work Like Chrome

I noticed a goofy issue today while working with a jQuery countdown plugin. This plugin allows you to set an “until” date so that you counter counts down to zero at a certain date and time.

I was setting the date like this:

element.countdown({
until: new Date(10/13/14 00:00:00)
});

In Chrome, this worked just fine. The string “10/13/14 00:00:00″ parsed to a Date object for midnight on October 13th, 2014.

In IE, however (versions10, 9 and 8 at least) it parsed as October 13th, 1914. Why? Who knows. Updating my string to “10/13/2014 00:00:00″ fixed it. My final javascript looked like this:

element.countdown({
until: new Date(10/13/2014 00:00:00)
});

So, be aware of this oddity! It caused my whole countdown widget to screw up because the current time was already past the “until” date.#

Sitefinity Thunder Boolean Widget Designer Field Auto-Generation is Flawed

##Problem

When you use Sitefinity Thunder (a great help, by the way) to generate a Widget Designer for an existing widget that has a boolean property, you get this javascript in the auto-generated javascript file (let’s say my boolean field is named HasSubMenu):

/* RefreshUI HasSubMenu */
jQuery(this.get_hasSubMenu()).attr("checked", controlData.HasSubMenu);

This code is in the refreshUI method. It’s supposed to mark a checkbox as checked if HasSubMenu is true and not check it if it’s false. The problem is, for some reason, HasSubMenu is a string in Javascript instead of a real boolean. So, HasSubMenu will be either “true” or “false”–both of which are true values in Javascript. That is, because “true” and “false” are both non-empty strings, they evaluate to true when used as an expression.

This means, no matter what you do with the checkbox, the next time you click “Edit” for this widget, the checkbox will be checked and your data is effectively corrupted.

##Solution

The solution is pretty simple. Instead of using controlData.HasSubMenu for the expression by itself, update your Javascript so that you check if the string is “true” or not: controlData.HasSubMenu === “true”. The line in the refreshUI method should now look like this:

/* RefreshUI HasSubMenu */
jQuery(this.get_hasSubMenu()).attr("checked", controlData.HasSubMenu === "true");

Now your checkbox will keep it’s value as you would expect.

Create a List Selector Field in a Widget Designer in Sitefinity 6.2

[9/25/14 update] See Hardy’s comments below for necessary updates to my steps when using Sitefinity 7.1 and up. Thanks, Hardy!

##Scenario

I am designing a fairly simple widget in Sitefinity (version 6.2, but this probably applies to other versions as well) that will display a simple FAQ list. The FAQ list has two major parts: 1) a “table of contents” type ordered-list at the top that lists each question and links to the answer further down the page, and 2) the list of questions with the answers below them.

##Approach

I wanted to create a simple Sitefinity list that would contain the FAQ content (questions and answers). The default fields for a Sitefinity list are Title and Content which are really all I needed to collect a Question and Answer for a FAQ item.

So, my widget, after being placed on a page, would only need to allow a content author to simply select the FAQ list they had created earlier. The widget would then find the list, collect the items in the list and display them.

##Solution

My solution would involved a widget designer control and a customized FlatSelector field. Here’s an overview with details below.

###Overview 1. Create a Sitefinity MVC widget with a single “List” field that will contain the list GUID 1. Create a Sitefinity widget designer for this MVC widget with a single FlatSelector field 1. Update the FlatSelector ItemType field 1. Update the FlatSelector ServiceURL field 1. Update the FlatSelector DataMembers 1. Update the widget designer Javascript to choose the list ID

###Details For some reason, Sitefinity widget designer documentation is really hard for me to find. Maybe I’m the only one. Maybe Sitefinity needs to put some more dollars toward good documentation! Anyway, after some searching and some trial and error, I found this page giving me an idea of how I should accomplish what I was trying to do: Sitefinity article

To summarize, it tells you how to create a widget designer with Sitefinity Thunder and then change the generated control to point to some of the generic content types (like Lists). However, it didn’t have all the details I needed. I had to troubleshoot and that’s why I’m writing this post.

####Step 1: Create the Widget Below are the details for how I setup my MVC widget. Translate the various tasks for the same effect if you prefer a WebForms widget.

Using Sitefinity Thunder, create your widget. Don’t create the designer at this time. I like using MVC widgets but there’s no reason this won’t work with a WebForms widget. I called my widget “FAQList”.

#####Step 1.1: Update controller properties Remove whatever properties Thunder automatically adds on the MVC controller and add your own List property of type Guid.

[Category("Widget Properties")]
public Guid List { get; set; }

#####Step 1.2: Update widget view model I added a simple POCO to describe each FAQ item (containing a question and answer) and then added a list of these POCOs as the only property on my view model.

public class FAQListModel
{
	public List<FAQItem> Items { get; set; }
}

public class FAQItem
{
	public string Answer { get; set; }
	public string Question { get; set; }
}

#####Step 1.3: Update Index action Update the Index action to use the List property to access the content-author-chosen list, pull the items and stick them in the model.

public ActionResult Index()
{
	var model = new FAQListModel();

	if (List != Guid.Empty)
	{
		model.Items = App.WorkWith()
			.List(List)
			.ListItems()
			.Get()
			.Where(li => li.Status == ContentLifecycleStatus.Live)
			.Select(li => new FAQItem { Question = li.Title, Answer = li.Content })
			.ToList();
	}
	else
	{
		model.Items = new List<FAQItem>();
	}

	return View("Default", model);
}

####Step 2: Create widget designer/public Once your widget is created, you can create your widget designer. Using Thunder, create a widget designer for an existing widget. Name your widget designer. I use the name of the widget and append “Designer”.

FAQItemDesigner widget designer naming

Click “Next” on the next screen. Choose your FAQItemController from the list on the next screen.

#####Step 2.1: Choose widget designer fields Next, choose the List property from your controller and set it up as follows. Especially note two things. First, choose the DynamicContentSelector. Second, update the “Select the content type for the selector” to ‘Telerik.Sitefinity.Lists.Model.List’. Click on “Add”.

Create a widget designer

#####Step 2.2: Update generated widget designer files In the generated .ascx file, update the ‘ServiceUrl’ property on the FlatSelector control to ‘/Sitefinity/Services/Lists/ListService.svc/?managerType=&providerName=&itemType=Telerik.Sitefinity.Lists.Model.List&provider=&sortExpression=LastModified%20DESC&skip=0&take=50’.

Service URL 1

In the generated .cs file, remove line 135 that sets the ConstantFilter property to ‘Visible=true’.

FAQItemDesigner remove line 135

Finally, in the generated .js file, change the property that is used as the value of the selected list from ‘OriginalContentId’ to ‘Id’. This code can be found in the ‘_ListDoneSelecting’ method.

FAQItemDesigner update js file

At this point, you should be done! Build your project, plop your new widget on a page and test it out! Here’s what mine looks like.

The edit dialog: FAQItemDesigner edit screen

The list select screen: FAQItemDesigner select screen

The selected item screen: FAQItemDesigner selected screen

EPiServer 7: Cannot decrypt password

##Problem I’ve been dealing with an issue in EPiServer 7 recently. I got this error when trying to log into the admin back-end of the site.

Cannot decrypt password

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Cannot decrypt password

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[InvalidOperationException: Cannot decrypt password]
EPiServer.Common.Security.HMACPasswordProvider.DecryptPassword(Byte[] ciphertext) +60
EPiServer.Common.Web.Authorization.Integrator.SynchronizeUser(MembershipUser membershipUser, String password, Boolean enableCreateNew) +1116
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165

##Scenario We originally installed the Relate+ site for our EPiServer installation. Through various bad decisions, we didn’t keep the custom code and templates we wrote separate from the Relate+ stuff. So, we inevitably created a mess where we did not need a ton of the Relate+ templates, page types, block types, etc but we could not longer easily pull our custom stuff out from the tangled mess.

Well, we undertook the disentangling anyway (a good decision) and ended up with a much cleaner code base. This meant re-installing EPiServer for a clean (without Relate+) beginning. The database would remain the same to keep our content.

We ran into this error when we got the new, cleaned-up site installed and running and then tried to log into the administration portion of the site.

##Solution At first, I found this post online: http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=77776 which suggested changing over to the multiplexing membership and role providers and described the new hashing mechanism in EPiServer 7.

At first, this seemed to work. Yay! But, the joy didn’t last long. I soon got the error again even after using the multiplexing providers. I dug a little deeper into the issue.

What I found was (in retrospect) pretty obvious. When we did the new, clean installation of EPiServer, it also created a new web.config with new attributes on the machineKey element. These properties are used with forms authentication to encrypt and decrypt information. Well, we didn’t make sure to keep the same values between the old install and the new install. So, when it tried to decrypt login information created with the old descryptionKey using the new decryptionKey, it obviously didn’t work.

Luckily, our trusty Systems Admins always keep backups of stuff they replace. We just went into the old web.config file from the previous site, copied the entire element and overwrite it in the new web.config. After an app pool recycle, the login was working great.

EPiServer 7 “The file ‘/link/GUID.aspx’ does not exist.” Error

I ran into the following error while working with an installation of EPiServer 7 this week. It took me a long time to finally figure out the solution.

First, here’s the error and stack trace:

2014-03-27 12:12:43,396 [6] ERROR EPiServer.Global: 1.2.5 Unhandled exception in ASP.NET
System.Web.HttpException (0x80004005): The file ‘/link/cc299342a697494c8a4bc47717210bf0.aspx’ does not exist.
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
at System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp)
at System.Web.Routing.PageRouteHandler.GetHttpHandler(RequestContext requestContext)
at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

As it turns out, I did not have a TemplateDescriptor attribute on the page template that I was trying to access. Adding the following TemplateDescriptor attribute to the code-behind class for my page template saved me.

[TemplateDescriptor(Path = "~/Templates/PageTemplates/Home.aspx")]
public partial class Home : TemplatePage<HomePage>