Tuesday, August 3, 2010

Adding a gallery in .NET 4.0 without requiring ClientIDMode in web.config

My previous blog post described how to add a gallery to a default ASP.NET 4.0 application. However, yesterday I noticed some strange behavior surrounding the new ClientIDMode property in .NET 4.0. It appears that in some cases you may have to specify ClientIDMode=“AutoID” in your application, but it doesn’t have to be in web.config. Read on for the details.

The tutorial in my previous blog post told you to replace the default web.config file with the .NET 4.0 version that ships with GSP. That version includes a couple attributes to tell GSP to use the legacy 3.5 behavior:

<pages theme="" styleSheetTheme="" validateRequest="false" controlRenderingCompatibilityVersion="3.5"
 clientIDMode="AutoID" />

If you use controlRenderingCompatibilityVersion and clientIDMode like this, I haven’t noticed any issues with GSP in .NET 4.0. If you are content with this, skip the rest of this post and go have a beer (preferably homebrew). Life is good.

But your app might be using the new client ID rendering features in .NET 4.0 and you don’t want to specify legacy behavior. Or you just don’t like the idea of putting your whole app in a legacy mode just because a piece needs it.

As best I can tell, GSP doesn’t need the controlRenderingCompatibilityVersion attribute, so go ahead and change it to “4.0” or delete it altogether.

But you can’t get rid of ClientIDMode so easily, nor use its default value of Predictable. In a stand-alone version of GSP, I can find one thing that breaks – the rearrange page.

Fixing the code on the Rearrange page

One of the really nice functions in GSP is the ability to drag the items in an album to reposition them:

rearrange1

But when ClientIDMode is left out of web.config or set to Predictable (or Static), you can no longer drag the thumbnails around. This turned out to be pretty easy to fix by changing one line of code in \gs\pages\task\rearrange.ascx:

onmousedown="<%# Container.ClientID %>.startDragging(event);">

Change it to this:

onmousedown="eval(this.parentNode.parentNode.id + '.startDragging(event);');">

You can make this change by just editing the file in a text editor like Notepad, and you do not have to recompile the source code. The next version of GSP will incorporate this fix.

I don’t really understand why the original code fails, since Container.ClientID should return the client-side name of the object. But the reality is that Container.ClientID returns a different ID than what is eventually output to the page, and this makes the javascript unhappy.

Does anything else break?

Well, it depends. In the stand-alone version of GSP (that is, when the gallery is the entire application), everything else seems to work. But when I add a gallery to an existing site, like I did in the tutorial, at least two of the ComponentArt controls failed – the Grid and Dialog controls. This breaks a bunch of stuff, including the image metadata window and several pages in the Site Admin area. For example, here is the Manage Users page:

users

I poked around for a bit, and I don’t know why it is failing. It is a mystery why it works when run as stand-alone app but not when added to an existing site. I tried it in both a default VB and C# ASP.NET 4.0 app and got the same (failing) results. If you have any theories let me know.

But the workaround is easy. Tell the gallery to use ClientIDMode=”AutoID”. This causes ASP.NET to generate client IDs the same way it did in earlier versions of .NET. By default, controls inherit this setting from their parent container, so you can set this once in web.config to get everything working very quickly. But, as I noted earlier, you might not want the entire app to use this mode. That leaves you with a few choices as to where you want to set it:

Page – Choose the .aspx page that contains the gallery and use a page directive to set it:

<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" 
    CodeBehind="Gallery.aspx.vb" Inherits="WebWithGsp.Gallery" ClientIDMode="AutoID" %>

Gallery control – Add the property to the top-level gallery control:

<gsp:Gallery ID="g" runat="server" ClientIDMode="AutoID" /> 

One or more child pages or controls – You can add this property to child user controls or server controls. For example, you could set it on the Manage Users page at gs\pages\admin\manageusers.ascx:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="manageusers.ascx.cs"
Inherits="GalleryServerPro.Web.gs.pages.admin.manageusers" ClientIDMode="AutoID" %>

But you would have to do it multiple times, which can be error prone (you might miss a few). Don’t do this. Just choose one of the top-level locations – web.config, .aspx page, or Gallery control, and set it there. Do it once and you are done. As with the edit to the rearrange page, you do not need to recompile the source code.

Hope this helps.

No comments: