24 February 2010

.NET app using Jet on x64

If you are trying to use an Access MDB file using the Microsoft Jet OleDb driver in .NET or ASP.NET, you must set your platform target to x86 (32 bit).

If you are running on a 64 bit system and your assembly target is Any CPU or x64 then you will see this exception:
The 'Microsoft.Jet.OLEDB.4.0' provider is not registered on the local machine.

The Microsoft ACE.OLEDB driver for MDB and ACCDB files works OK whichever platform is targeted. However this driver is not installed by default on user computers unlike the Jet driver.

This fix can be used to make existing code work with Jet/MDB, eg the Cassini server.

Useful blog links:

22 February 2010

System.String hidden UTF8 BOM

In .NET, a string (System.String) can contain an initial UTF-8 Byte Order Mark (BOM) which might not be seen in ordinary processing but is present when converted to a character array or into an encoding byte array.

For example, a text file might be saved in UTF8 format with UTF-8 Byte Order Mark bytes at the start, ie 0xEF 0xBB 0xBF. You might receive this file in ASP.NET using a FileUpload control, or read it directly in a Forms .NET app in C#:

byte[] FileBytes = File.ReadAllBytes(path);
string content = Encoding.UTF8.GetString(FileBytes);

If the file contains these 7 bytes (in hex) EF BB BF 44 65 61 72 then content will superficially contain the single word "Dear", eg as seen in the debugger, and content.StartsWith("Dear") will return true.

However, content.Length is 5 and content.ToCharArray() will return an array with 5 elements, the first being set to 0xFEFF. Similarly, Encoding.UTF8.GetBytes(content) will return the same 7 bytes as was used in the first place.

(Note that that has nothing to do with the encoderShouldEmitUTF8Identifier optional parameter for the UTF8Encoding constructor.)

As this hidden extra character can be misleading, I have written the following snippet that detects the presence of the UTF8 Byte Order Mark preamble and ignores it if present:

byte[] FileBytes = File.ReadAllBytes(path);
int StartPoint = 0;
int Count = FileBytes.Length;
if ( Count>= 3 && FileBytes[0] == 0xEF && FileBytes[1] == 0xBB && FileBytes[2] == 0xBF)
StartPoint += 3;
Count -= 3;
content = Encoding.UTF8.GetString(FileBytes, StartPoint, Count);

PS The code could not doubt be improved using Encoding.GetPreamble()

07 February 2010

Clearing nested CSS floats

Here's a XHTML/CSS technique to ensure you only clear the desired floats and get the right background areas for your DIV.

The code examples are here: http://www.phdcc.com/CSS_ClearingFloats.htm - look at the source code for full details.

My starting point is to have a DIV set with floats left and right. Within the middle unfloated DIV, I have another DIV set with floats and right. I want to clear just the middle floats, not the outer ones.

The crucial trick is to add CSS style 'overflow:hidden' to create a Block Formatting Context. Any CSS style 'clear:both' then only applies to the 'nearest'/current Block Formatting Context.

An associated problem was the fact that the background of the middle unfloated DIV goes wide to the border of the current Block Formatting Context. Adding CSS style 'overflow:hidden' to create a new context constrains the background to the expected area.

Using 'overflow:hidden' feels slightly naff: shouldn't there be an explicit CSS style to define a Block Formatting Context, instead of using something that does this as a side effect? Also, you may be concerned about what overflow is being hidden - as long as you have the default width:auto and/or height:auto set, you will not be hiding anything.

05 February 2010

Adding Access key support to DotNetNuke

This page explains how to add "access key" support to a DNN5 web site.
Access keys provide keyboard short-cuts to improve web accessibility, as described here - which also lists the UK government recommendations:

I have implemented access keys using the accesskey attribute rather than the
Role Access Model

How it works for a user

For standard users, each browser uses different modifier keys and acts minorly differently when pressed. Consider accesskey '1'. In Windows Internet Explorer, pressing Alt+1 selects the corresponding link - you must press Enter to go to that link. In Firefox, pressing Alt+Shift+1 goes to the associated link immediately.

These accesskey shortcuts take precedence over standard Window commands, so if you define an accesskey 'f' it will be acted on rather than show the File menu in Windows.

In Internet Explorer, the link is not selected if the link has a style of display:none.

Search accesskey

Most of the access keys can be defined in your DNN skin using extra HTML that is not normally seen. However, accesskey 4 takes you straight to the Search text box. To make this happen, I had to amend admin/Skins/search.ascx to add AccessKey="4" to the txtSearchNew asp:TextBox.

While there, I took the opportunity to add a label for this box, as recommended for all fields to improve accessibility. This label is present but not normally displayed:
<asp:Label AssociatedControlID="txtSearchNew" style="display:none;" runat="server">Search:</asp:Label>

Main accesskeys

The main site access keys can be defined using code like this at the top of your skin, which I adapted from another web site:

<ul id="skips">
<li><a href="#content" accesskey="s">Skip to page content, accesskey=s</a></li>
<li><asp:HyperLink ID="SkipToHome" NavigateUrl="~/" AccessKey="1" runat="server">Skip to Home page, accesskey=1</asp:HyperLink></li>

CSS (below) can then be used to make sure that this information is not normally seen, but each link become visible when it has the focus or is active. The list-style is set to none to avoid bullet points etc. When not in focus, the links have width and height 0; when in focus these are set to auto. Tweak the other settings as you wish.

Finally, don't forget to provide an anchor within your skin for the skip to navigation link:
<a id="content" name="content"></a>

CSS code:
ul#skips { list-style: none; }
#skips li { list-style: none; display: inline; }
#skips a
color: white; width: 0; height: 0; overflow: hidden; z-index: 1000;
position: absolute; top: 15px; left: 100px;
#skips a:active, #skips a:focus
color: red; border: 1px solid red;
width: auto; height: auto;
display: block; overflow: visible;
padding: 3px;

01 February 2010

DNN local install with SQL Server

The post summarises the steps required to set up DotNetNuke 5 (DNN5) locally on Windows using the full Microsoft SQL Server using SQL Server authentication, ie not the Express version. Getting the Logins and Users right is the crucial trick that I want to remember.

Click on each image to see it larger.

  1. In Microsoft SQL Server Management Studio, connect to your local server. Right-click on Databases on the left. Select "New database". In the following screen, enter a database name, eg "DNN522pen" and click OK without changing anything else.

  2. Now, find the server Security and right-click on Logins and select "New Login...":

  3. Enter a login name such as "dnn522pen", select "SQL Server Authentication" and enter the password. Untick "Enforce password policy" if you wish. Do not set the Default database. Click OK.

  4. Open up your database tree on the left: open "dnn522pen" then Security then Users. Right-click and select "New user...":

  5. In the new user dialog, enter a User name such as "dnn522pen" and the Login name you used before eg "dnn522pen". Tick "db_owner" twice below and click OK:

  6. Next, create a new folder on disk somewhere, eg in directory "D:\dnn522pen\". Unzip the DotNetNuke community installation file in there DotNetNuke_Community_05.02.02_Install.zip.

  7. Open up Internet Information Services (IIS 7) Manager. Expand the menu on the left to open Sites and Default Web Site. Click on "Add Application..." on the right.

  8. Enter a suitable alias and physical path, eg "dnn522pen" and "D:\dnn522pen\":

  9. In IIS Manager, select the new alias on the left, select Content View and click "Browse" to start the DNN installation:

  10. After a delay you should see the first DNN install screen. Choose custom:

  11. Test file permissions.

  12. Now, set up your database connection:

    • First, click on "SQL Server 2005/2008 Database" and wait for the screen to refresh

    • Enter "(local)" for the Server

    • Enter the database name, eg "dnn522pen"

    • Uncheck "Integrated Security" and wait for the screen to refresh

    • Enter the User ID and password

    • Keep "Run as db Owner" checked

    • If desired, enter a database table name qualifier, eg "DNN_"

    • Click on "Test Database Connection"

    • If OK, click on Next

  13. Proceed with the rest of the DNN installation as normal.