Sunday, July 15, 2007

Making Web Setup projects run on Windows Vista

Windows Vista offers many enhancements over previous operating systems. Unfortunately for us developers it also presents some challenges. One such challenge is making a Web Setup project run on Windows Vista. This post shows step-by-step how to make it work.

Windows Vista comes pre-configured with IIS 7. Unfortunately, Web Setup projects do not recognize IIS 7 and therefore will fail when you attempt to run it on Windows Vista. In my case, the failure is presented as shown in the following figure.

Doing a lot of searching in Google presented me with nothing really obvious. As you can see from the figure above, the error message is not really helpful. Luckily, while searching for something else, I stumbled onto a MSDN article titled Troubleshooting Windows Installer Deployment. In the article I found the section Web Setup deployment projects in Visual Studio 2005 on Windows Vista, as a new section for Visual Studio 2005 SP1. The section says

When you create a Web Setup deployment project in Visual Studio 2005 on Windows Vista, you need to turn on the Windows feature IIS Metabase and IIS 6 configuration compatibility, and you need to be logged on as an Administrator; otherwise you will be unable to run setup.exe to install the project.

In order to turn on the Windows feature you can follow these steps:

1. Launch Control Panel and select Programs. This will display the Programs options.

2. In the Programs options select Turn Windows features on or off. This will display the Windows Features dialog.

3. In the Windows Features dialog expand the branch as shown in the following figure to finally select IIS Metabase and IIS 6 configuration compatibility. Select OK to install the feature.

Let Windows complete the installation. Once complete you will be able to run your Web Setup project on Windows Vista.

Read full post...

Thursday, May 31, 2007

Automatically launch a silent remote MSI installation from Team Build

If you need to maintain an up-to-date test machine with the latest installation of the product you are testing, this post shows you how you can trigger the automatic installation of the latest components as a result of a successful build.

The logic has been tested using Team Build. However, since the underlying technology is MSBuild, the information described here does not require Team Build.

Prerequisites

MSBuild, and therefore Team Build, is unable to natively build Setup projects. In order to build a Setup project from within a Build Type you need to use the Visual Studio environment via the command line. This implies you will need to have access to Visual Studio. Preferably, the Visual Studio environment should be installed on the Build Machine.

In addition, because the Build Machine will be triggering the execution of the installation remotely, the user account under which the build process executes should have remote, administrative access to the Test Machine on which the installation will occur. Alternatively, you may use another user credentials to execute the installation but this means that these credentials will need to be part of the command that will launch the remote process, and therefore part of the Build Type project file.

Required Tools

Devenv - Executable used to launch Visual Studio. It can be used to build Setup projects from the command line, amongst other things. For details on all command line switches for Devenv refer to the MSDN online documentation. For details on building Setup projects using Team Build, please refer to the article Walkthrough: Configuring Team Foundation Build to Build a Visual Studio Setup Project.

PsExec - Allows execution of processes on other systems. PsExec is part of the Windows Sysinternals download and it is hosted at Microsoft TechNet.

Msiexec - The resulting MSI from a Setup project is not an executable. In order to perform actions outside of its default association, you require the use of a tool called Msiexec. This tool provides the means to install, modify, and perform operations on Windows Installer from the command line. Silent execution of these Windows Installer files can be accomplished through Msiexec.

Combining the Tools

In order to build a Setup project you need to use an Exec task in the AfterCompile target, as the following code snippet shows.

<Target Name="AfterCompile">
  ...
  <Exec Command="$(DevEnv) &quot;$(SolutionRoot)\Setup\Setup.vdproj&quot; /Build &quot;Release|Any CPU&quot;"/>
  ...
</Target>

Once you have access to the resulting MSI file, you can use the following command to execute a remote installation. Note that you will need to replace the information such as Server Name (MyServerName in the example below) and paths with yours.

<Target Name="AfterCompile">
  ...
  <Copy SourceFiles="$(SolutionRoot)\Setup\Release\Setup.msi" DestinationFolder="\\MyServerName\C$\Temp\Setup" />
  <Exec Command="$(PsExec) \\MyServerName -w &quot;C:\Temp\Setup&quot; msiexec /i &quot;C:\Temp\Setup\Setup.msi&quot; -quiet"/>
  ...
</Target>

Note: There have been cases where PsExec causes MSBuild to hang in the middle of a remote installation. I have yet to figure out why this may happen. If you run into this scenario and are able to fix it please share your experiences.

Alternate Scenario

There are times when you may want to trigger the installation on a remote machine from within your Visual Studio environment. For example, I do this often when I perform integration testing of MSBuild custom tasks, where I need to install the custom task in the Build Machine. Rather than doing it manually, I make it part of the Setup project's Post-build event.

I use the following script to automate the installation of my setups. In order for you to use the script, add it to your own Setup project's Post-build event and replace all the lines in bold with your own information.

echo ======================================================================
echo POSTBUILDSTEP for setup project.
 
set ServerName=YOUR_SERVER_NAME
set ServerPath=\\%ServerName%
set RemoteDrive=C
set MsiPath=Temp\YourProjectName
set MsiName=YourProjectNameSetup.msi
set RemoteMsiFilePath=%RemoteDrive%:\%MsiPath%
set RemoteMsiFileName=%RemoteMsiFilePath%\%MsiName%
set UncMsiFilePath=%ServerPath%\%RemoteDrive%$\%MsiPath%
 
echo Verifying/Creating temporary folder at "%UncMsiFilePath%"
if not exist "%UncMsiFilePath%" mkdir "%UncMsiFilePath%"
if errorlevel 1 goto BuildEventFailed
 
echo Uninstalling "%RemoteMsiFileName%" from server %ServerName%
psexec %ServerPath% -w "%RemoteMsiFilePath%" msiexec /uninstall "%RemoteMsiFileName%" -quiet
if errorlevel 1619 goto BuildEventContinue
if errorlevel 1606 goto BuildEventFailed
if errorlevel 1605 goto BuildEventContinue
if errorlevel 1 goto BuildEventFailed
 
:BuildEventContinue
echo Copying "$(BuiltOuputPath)" to "%UncMsiFilePath%"
xcopy /Y /R "$(BuiltOuputPath)" "%UncMsiFilePath%"
if errorlevel 1 goto BuildEventFailed
 
echo Installing "%RemoteMsiFileName%" on server %ServerName%
psexec "%ServerPath%" -w "%RemoteMsiFilePath%" msiexec /i "%RemoteMsiFileName%" -quiet
if errorlevel 1 goto BuildEventFailed
goto BuildEventOK
 
:BuildEventFailed
echo POSTBUILDSTEP for setup project FAILED
exit 1
 
:BuildEventOK
echo POSTBUILDSTEP for setup project COMPLETED OK
echo ======================================================================
echo.

With the script in place, whenever I build the Setup project the script will uninstall any previous version and re-install the new version of my custom task. This technique can be applied to pretty much any type of Setup project.

Read full post...

Wednesday, May 30, 2007

VSTS Database Professional using Remote SQL Server

My local SQL Server 2005 installation was damaged and I needed to be able to continue work on a project that makes use of the Visual Studio 2005 Team Edition for Database Professionals (VSTS DB Pro). The problem is that VSTS DB Pro requires a local SQL Server 2005 Developer Edition instance and above for it to work. So how does one make use of a remote SQL Server instance?

Perhaps there's another way to make it work with a remote SQL Server instance, but it appears that the current version of VSTS DB Pro does not natively support such configuration.

Luckily I found a MSDN Forum Post where Thomas Waldron suggests the use of a tool called TcpTrace to redirect the local 1433 port to that of a remote SQL Server instance. It works like a charm! I can now load my database projects.

Read full post...

Wednesday, March 28, 2007

Digg This plugin for Windows Live Writer

Update (08/01/07): Source code now available on CodePlex.

Digg This plugin for Windows Live Writer is a plugin to insert a "Digg This" button into to your Windows Live Writer posts. It is a wrapper to the API described in the Integrate: "Digg This" Button page at Digg.

Digg This Sidebar Editor

If you already use Digg, you will surely know how to use this plugin. The functionality is designed to closely match the online submission form. The Sidebar editor is broken into two tabs: General and Appearance.

The General tab contains the information used as defaults for the submission to Digg. The Appearance tab contains properties that allow you to modify the way the Digg This button will look when published.

The simplest way to use this plugin is to specify a post title, specify at least one paragraph of text that will describe briefly the post, place the cursor wherever you would like to insert the Digg This button and click on the Insert Digg This... option in the Sidebar. You will notice that the post title is used for the submission title and the first paragraph is used for the submission text. The first time one of your readers clicks on the button once the post is published, they will be sent to the Digg site to submit the post to Digg. The defaults you specified will appear for the user to either use as is, or modify accordingly.

Some of the features of the Digg This plugin are:

Auto-selection of Title & Text – The Digg This button has the ability to accept recommendations or defaults as part of the submission link. These parameters are used to pre-populate the respective fields when a user submits an entry. Instead of having the submitter type their own text, which they can still do during submission time, the Digg This plugin will take the post’s title and the first paragraph in the post body and use these as the suggested Title and Text properties in the Windows Live Writer Sidebar, respectively.

Submission Character Count – Just like the online submission form on Digg for the Title and Text fields, the number of remaining characters available will appear in the status bar of the Windows Live Writer Sidebar.

Visual Layout of Digg This Button – Using the Appearance features present in the Windows Live Writer Sidebar when the object is selected, you can modify the Layout, Text Wrapping, and Margin properties and see them apply immediately.

Tooltip Help – All fields have an associated tool tip that provides more details about the specific use of that field.

Persistent Options – Changes to the Digg This properties can be used as defaults. These include layout and submission properties, accept for Title and Text, which get overwritten whenever a new instance of the Digg This button is inserted in a post.

Download Digg This plugin for Windows Live Writer Setup

Read full post...

Friday, February 23, 2007

NHibernateProvider - Membership/Role provider using NHibernate

I started this project last year to get myself more involved in learning alternative persistence mechanisms to use with ASP.NET. NHibernateProvider is an ASP.NET 2.0 Membership/Role provider using NHibernate.

In case you don't already know, NHibernate is a port to .NET of the Hibernate Core for Java. Hibernate is an Object-relational mapping (ORM) solution for the Java language (see more at Wikipedia).

The project has been hosted at GotDotNet for the past few months, but it appears that GotDotNet is being phased out. So, I decided to take this opportunity to not only move the project to CodePlex, but also to do a formal RTM release. It had been in Beta for a while now with no apparent issues.

You can find the details of this release and of the entire project at it's new home at CodePlex.

Read full post...

Monday, February 19, 2007

Creating a customized Manual Test template for Visual Studio 2005

Update (01/12/2008): The post has been updated to show the differences with respect to Visual Studio 2008. The corresponding notes have been written in blue.

Part of the work we do at InCycle Software is help our customers install and configure Visual Studio Team System (VSTS). This includes the customization of work items, reports, process guidance, etc. For some customers, we even help them customize some of the templates.

Visual Studio 2005 Team Suite and Visual Studio 2005 Team Edition for Software Testers have templates specific to testing. One of these test templates is the Manual Test. There are two Manual Test formats: Text and Word. The steps to follow will show you one way to customize the look and structure of the Word format document and package it to create your own template.

I will assume that you are somewhat familiar with the Visual Studio environment and that you already know how to create Solutions and Projects. For these and other walkthroughs please refer to the Samples and Walkthroughs pages in MSDN.

The testing templates in Visual Studio 2005 are nothing more than extensions to the environment. In order to create a complete extension you would need to use the Visual Studio SDK. Creating a full Visual Studio extension is beyond the scope of this post.

With the help from Sarah Cameron, one of my colleagues at work, we have polished and divided the process into three main steps.

Create the Template

1. Start with the existing Manual Test template that can be found in your Visual Studio's Item Template folder. In my installation the path is D:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\CSharp\1033. The template file name is ManualTestWordFormat.zip.

Note: In Visual Studio 2008 the above path would be D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates\CSharp\1033. The template file name is the same. The path varies from Microsoft Visual Studio 8 to Microsoft Visual Studio 9.0.

2. Create a folder that will contain your customized template files. In this example, I will call the folder InCycleManualTest. This will serve as a staging area and is really optional.

3. Extract the contents of the ManualTestWordFormat.zip into the InCycleManualTest folder. The folder should now contain two files: ManualTest.mht and ManualTest.vstemplate.

4. Rename both extracted files to match the name of your template folder. In this example, the files are renamed to InCycleManualTest.mht and InCycleManualTest.vstemplate, respectively.

5. Open the .mht file in Microsoft Word and modify the document to suit your needs. When you are done you can save the document and close Word. You now have the document template contents for your customized Manual Test.

6. Open the file .vstemplate in a text editor such as Notepad. You should see the contents as an XML-formatted document. The document looks like the following.

<VSTemplate Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Item">
<TemplateData>
<Name Package="{52CBD135-1F97-2580-011F-C7CD052E44DE}" ID="113"/>
<Description Package="{52CBD135-1F97-2580-011F-C7CD052E44DE}" ID="109"/>
<Icon Package="{52CBD135-1F97-2580-011F-C7CD052E44DE}" ID="107"/>
<ProjectType>CSharp</ProjectType>
<SortOrder>10</SortOrder>
<DefaultName>ManualTest.mht</DefaultName>
<TemplateGroupID>TestProject-V1</TemplateGroupID>
<TemplateID>TestProject-V1-WordManualTest</TemplateID>
</TemplateData>
<TemplateContent>
<ProjectItem ReplaceParameters="false" OpenInEditor="true">ManualTest.mht</ProjectItem>
</TemplateContent>
<TestProjectData>
<LongDescription Package="{52CBD135-1F97-2580-011F-C7CD052E44DE}" ID="112"/>
<Helpkeyword Package="{52CBD135-1F97-2580-011F-C7CD052E44DE}" ID="105"/>
</TestProjectData>
<WizardExtension>
<Assembly>Microsoft.VisualStudio.QualityTools.Wizard.TestProjectWizards</Assembly>
<FullClassName>Microsoft.VisualStudio.TestTools.TestProjectWizards.TestItemWizardExtension</FullClassName>
</WizardExtension>
</VSTemplate>

Note: In Visual Studio 2008, the Version of the VSTemplate is 3.0.0. If you start with the template from the correct folder you will already have this version set correctly.

At this point the document represents the Manual Test Word format item template. We need to make some changes to add our customized template specific information.

Specifically update the following tags: Name, Description, DefaultName, TemplateID, and ProjectItem. Remove or replace the contents of the TestProjectData tag.

Save the document.

Note: It is very important that the TemplateID is unique. If it matches an existing template it will override its associated document.

Note: If you want to use special characters in the Name or Description of the template you will need to use the equivalent escape character (same XML rules apply to the .vstemplate document). For example, if you want to include a word that contains the French character "é" (no quotes) then you will need to replace it with its equivalent escape character "&#233;" (no quotes). Failing to do so will cause the template to fail registration without any error message.

The following is the resulting InCycleManualTest.vstemplate file used in this example.

<VSTemplate Version="2.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/developer/vstemplate/2005">
<TemplateData>
<Name>InCycle Manual Test (Word format)</Name>
<Description>Customized manual template</Description>
<Icon Package="{52CBD135-1F97-2580-011F-C7CD052E44DE}" ID="107"/>
<ProjectType>CSharp</ProjectType>
<SortOrder>80</SortOrder>
<DefaultName>InCycleManualTest.mht</DefaultName>
<TemplateGroupID>TestProject-V1</TemplateGroupID>
<TemplateID>InCycleManualTest</TemplateID>
<ShowByDefault>false</ShowByDefault>
</TemplateData>
<TemplateContent>
<ProjectItem ReplaceParameters="true" OpenInEditor="false">InCycleManualTest.mht</ProjectItem>
</TemplateContent>
<WizardExtension>
<Assembly>Microsoft.VisualStudio.QualityTools.Wizard.TestProjectWizards</Assembly>
<FullClassName>Microsoft.VisualStudio.TestTools.TestProjectWizards.TestItemWizardExtension</FullClassName>
</WizardExtension>
</VSTemplate>

7. Repackage the files you previously extracted and modified into a zip file and call it the same name as the folder you created. In this example, the compressed file is called IncycleManualTest.zip. Verify that the zip file does contain your two files and that these files do have your changes.

Note: It is very important that the files reside in the root of the zip file. If not, the template will not register correctly.

Deploy the Template

8. Copy the modified exported template zip file to your Visual Studio's Item Template folder. In this example, I copy the file IncycleManualTest.zip to my folder D:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\CSharp\1033.

9. If updating an existing template you must first remove any previous template from Visual Studio’s Item Template Cache, which gets copied during the initial installation.

For example, if updating the IncycleManualTest.zip template I would remove the corresponding IncycleManualTest.zip file from my folder D:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplatesCache\CSharp\1033 before installing the new template. This is to ensure the new template is correctly updated in the cache.

10. Install your customized template. For the template installation command to work correctly you need to run the Visual Studio 2005 Command Prompt, as it initializes some environment variables required for the execution of the command.

The Visual Studio 2005 Command Prompt can be found under your Start menu. Look for the program group Microsoft Visual Studio 2005 / Visual Studio Tools. Launch it.

At this point, make sure you close any running instances of Visual Studio. At the command prompt type and execute the command devenv /InstallVSTemplates.

Visual Studio 2005 Command Prompt (click for full size)

Give it some time to complete. Note that even after the command prompt returns your hard disk may continue spinning. So, give it some more time to make sure the registration is finalized.

Test the Template

11. Test your new template. Launch Visual Studio and open/create a Test Project. Select New Test... like you did before to display the Add New Test dialog. You should now see your new Manual Test template.

Add New Test dialog with Custom template (click for full size)

In order to do a complete test of this template you should create multiple Manual Test using it and go through the paces to make sure the template is recognized in the Test View.

Read full post...

Wednesday, February 14, 2007

Sudden SQL error during INSERT/UPDATE operation (ARITHABORT)

Your database has been running fine for the longest time. All of a sudden INSERT or UPDATE operations fail with an error similar to the following.

UPDATE failed because the following SET options have incorrect settings: 'ARITHABORT'

Quick research tells you to simply add the following line right after you open a connection to the database or at the start of your query.

SET ARITHABORT ON

This seems to make things work again, but have you really solved the problem?

It turns out that this error is caused when you create an Indexed View. But I didn't do it? Well, if you run either the Index Tuning Wizard (SQL Server 2000) or Database Engine Tuning Advisor (SQL Server 2005), they will create what are called "Hypothetical Materialized Views" or index views. These views start with the prefix _hypmv. When the analysis is finished these views are supposed to be discarded. However, if for whatever reason these views are not deleted, any attempts to INSERT or UPDATE into the table(s) on which this indexed views were created, the error message relating to incorrect ARITHABORT setting will occur.

In my particular case, the reason why these views were not discarded was because my account had enough privileges to create these views but not delete them. Running the tuning tools would leave these indexed views behind without me realizing it.

So, if you see this error it may be that you have left behind some indexed views you did not create directly. Deleting them should get rid of the error.

Read full post...

Monday, February 12, 2007

Code Snippet plugin for Windows Live Writer

Update (03/18/09): Version 2.0.0 released, please refer to this post for details.
Update (03/16/09): Version 2.0.0 – Preview is now available on CodePlex.
Update (08/01/07): Source code now available on CodePlex.
Update (03/26/07): Version 1.0.2 is now available with
new features.
Update (02/27/07): Version 1.0.1 is now available with
new features.
Update (02/21/07): You can now download the plugin from the Windows Live Gallery

I use Windows Live Writer (WLW) to post to my blog. As of this writing, WLW is in Beta. Nonetheless, the features available are very functional and I have to say that I have nothing but pleasant experiences using the product so far.

One of WLW features of interest to the geek in me is its support for plugins via its SDK. As you may already know, a plugin allows developers to extend an application with additional features.

A good part of my posts contain source code snippets to illustrate and/or compliment the content. Instead of using plain text to represent the code snippets I have been using CSS-based syntax highlighting thanks to the online code formatter written by Jean-Claude Manoli.

When I started using WLW I looked for plugins to see what useful features others have created. The Writer Windows Live Gallery has a growing list of plugins. I had found the Insert Formatted Clipboard, Paste from Visual Studio and Insert Code for Windows Live Writer, all for formatting and/or applying syntax highlighting to sample source code. But while using them I found that there were things I wanted to do that these plugins did not offer. So, I wrote the Code Snippet plugin based on the syntax-highlighting code that Jean-Claude made public.

The following image shows the main Code Snippet window that you can use to interactively review the sample code before inserting into your post.

Code Snippet dialog - Full Mode (click for full image)

Some of the features in the Code Snippet plugin are:

Run Silent - use latest settings to automatically process current clipboard contents for quick pasting without displaying the Code Snippet dialog. Press and hold the Ctrl key while activating the plugin to return to previous mode (Full or Compact).
Rich Text Editor - lets you perform final changes to the source code before pasting it into your blog post. I work with a lot of source-controlled code that I don't want to necessarily touch in that environment prior to posting. So, I wanted to have the ability to increase/decrease indents or make changes to namespaces or class names without pasting to other text editors as an intermediary step.
Expandable/Splitable Code Panes - able to view the code to process or the formatted code using the entire dialog space, in addition to viewing both contents in split mode.
Persistent Options - any changes to the options are automatically stored in an external configuration file and reloaded on next execution.
View HTML - you can view the HTML markup before inserting the code snippet.

Update (02/27/07): New features in version 1.0.1.

Compact Mode - in addition to the Full Mode, you can now also work with a compact version of the dialog that allows you to quickly select the formatting options without a preview. Switching between Full and Compact Modes is quick and painless by pressing the F12 key. The following figure shows the Compact Mode dialog for the plugin.

Code Snippet dialog - Compact Mode

Window Placement Persistence - in addition to automatically storing formatting and other options, now the window location, size, and other characteristics are also remembered.
Copy CSS Style to Clipboard - to make it easier to extract the stylesheet for inclusion in your blog's template, you can now easily copy the contents to the clipboard.

Update (03/26/07): New features in version 1.0.2.

Support for CSS snippets - Added support for syntax highlighting Cascading Style Sheets (CSS) snippets.
Embedded Styles Now Inline - Changed implementation used for embedding styles from using the class attribute to using the style attribute. The former assumed embedding the stylesheet classes as part of the generated HTML for the code snippet. The latter uses inline definitions, which proves to be friendlier to RSS feeds and e-mail delivery where the embedded CSS is not recognized.

Update (03/16/09): New features in version 2.0.0.

Please refer to the CodePlex release page here for all the details.

Download Code Snippet plugin for Windows Live Writer v1.0.2

Download Code Snippet plugin for Windows Live Writer v2.0.0 - Preview

Read full post...

Sunday, February 4, 2007

Improve performance when using WindowsTokenRoleProvider with lots of roles

This post got longer than anticipated. So, I broke it down into sections so you can dive right in.</> You don't need to read the Preface section if you're already familiar with how ASP.NET 2.0 implements authentication/authorization.

Preface

ASP.NET 2.0 has built-in support for Authentication and Authorization via its Provider Model. It comes with ready-to-use classes for Integrated Windows Authentication and for role management via WindowsTokenRoleProvider. You can read this article for all the details on how to configure these and other providers to secure your application. This post is focusing only on authentication and authorization against Active Directory (AD).

The short of securing your application is to add the following to your Web.config file.

<authentication mode="Windows" />
<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider" />


This will enable authentication using the user's current identity and authorization using the user's AD Group Memberships as the roles.

To ensure IIS passes the user's identity to ASP.NET you need to enable it for the site by setting the Integrated Windows Authentication flag in the Authentication Methods dialog of the site properties Directory Security tab.

IIS Directory Security

Once authentication/authorization is enabled, ASP.NET will verify every HTTP request to ensure only allowed content is returned to the browser. It does this by checking the authorization rules you specify either in your Web.config file on as part of a site map definition that has trimming enabled.

Normally, the process of verifying access to different pages in you application will happen very fast. Nonetheless, you can release some of the burden of accessing AD for every request by enabling caching in the roleManager. To do this you can set the attribute cacheRolesInCookie in the roleManager definition.

<roleManager enabled="true" cacheRolesInCookie="true" defaultProvider="AspNetWindowsTokenRoleProvider" />

This will store the roles for the logged in user in a cookie that gets sent back and forth between server and client and back.

Problem

As you may already know, cookies have a limit of 4096 bytes. If you enable caching in the roleManager and your users have deeply nested group memberships in AD, this limit can be easily exhausted. The result is very slow performance even when caching is enabled.

Solution

One possible way to get around this limitation is to extend the default WindowsTokenRoleProvider to compress the contents of the cookie. The drawback I see with this approach is that the cookie is traveling back and forth from client to server to client and back. Another drawback is the fact that custom code to parse the contents of the cookie needs to be written in order to extract the roles before passing them to the base implementation.

My preferred solution still involves writing custom code, but not to parse any cookies. The implementation still extends the WindowsTokenRoleProvider, but performs the caching on the server side instead, using the HttpContext.Cache as shown in the following sample code.

using System.Web;
using System.Web.Caching;
using System.Web.Security;

// Recommended namespace is YourApplication.Web.Security. Essentially create a project that
// follows the same namespace naming conversion as ASP.NET but instead of System use your
// application name.
namespace YouNamespace
{
/// <summary>
/// Provides role information for an ASP.NET application from Windows group membership.
/// </summary>
/// <remarks>
/// Overriden to add proper caching of roles.
/// </remarks>
class WindowsTokenCachingRoleProvider : WindowsTokenRoleProvider
{
/// <summary>
/// Required for provider model.
/// </summary>
public WindowsTokenCachingRoleProvider()
{
}
/// <summary>
/// Gets a list of the Windows groups that a user is in.
/// </summary>
/// <param name="username">
/// The user to return the list of Windows groups for in the form DOMAIN\username.
/// </param>
/// <returns>
/// A string array containing the names of all the Windows groups that the specified
/// user is in.
/// </returns>
public override string[] GetRolesForUser(string username)
{
// List of Windows groups for the given user.
string[] roles;

// Create a key for the requested user.
string cacheKey = username + ":" + base.ApplicationName;

// Get the cache for the current HTTP request.
Cache cache = HttpContext.Current.Cache;
// Attempt to fetch the list of roles from the cache.
roles = cache[cacheKey] as string[];
// If the list is not in the cache we will need to request it.
if (null == roles)
{
// Allow the base implementation to load the list of roles.
roles = base.GetRolesForUser(username);
// Add the resulting list to the cache.
cache.Insert(cacheKey, roles, null, Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration);
}

// Return the resulting list of roles.
return roles;
}
}
}

With this code in place, you can now replace the default roleManager definition with the newly extended WindowsTokenCachingRoleProvider by replacing the corresponding Web.config file entry with the following.

<roleManager enabled="true" defaultProvider="AspNetWindowsTokenCachingRoleProvider">
<providers>
<add name="AspNetWindowsTokenCachingRoleProvider" applicationName="/" type="YouNamespace.WindowsTokenCachingRoleProvider, YourAssembly" />
</providers>
</roleManager>

Using this method I have seen major improvements for those users who happen to be members of many AD groups.

Read full post...

Saturday, January 27, 2007

SQL-equivalent to NVL2

I have been using T-SQL for as long as I can remember and one of the things I never found was an equivalent to Oracle's NVL2. Well, this time around I did not want to use a CASE statement or even the more involved COALESCE. I just needed a plain function that would evaluate if the given expression is null return this otherwise return this.

The following T-SQL function will provide the equivalent to NVL2, or at least something close enough. The trick is to use the sql_variant data type.

IF EXISTS (SELECT id
FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'[dbo].[isnull2]')
AND xtype in (N'FN', N'IF', N'TF'))
BEGIN
DROP FUNCTION [dbo].[isnull2]
END
GO
CREATE FUNCTION [dbo].[isnull2]
(
@expression sql_variant,
@return_if_null_value sql_variant,
@return_if_not_null_value sql_variant
)
RETURNS sql_variant
AS
BEGIN
DECLARE @return sql_variant;
IF (@expression IS NULL)
SET @return = @return_if_null_value
ELSE
SET @return = @return_if_not_null_value
RETURN @return
END

Please note that you will need to ensure you cast either the parameters you pass or the result to the desired type. This is specially true if you are calling the logic in a stored procedure or embedded query that is executed from a .NET or similar application via something like ADO.NET.

Read full post...

How to get the SmartAutoCompleteExtender to work with ASP.NET AJAX 1.0 RTM

If you are using the SmartAutoCompleteExtender by Infinities Loop with pre-release versions of Atlas, and you just upgraded to the new ASP.NET AJAX 1.0 RTM release, you will have to make some minor changes to the SmartAutoCompleteExtender code for it to work again.

1. In the project where the SmartAutoCompleteExtender resides, add a reference to the AjaxControlToolkit.dll assembly. This is now required since the AutoCompleteExtender, on which the SmartAutoCompleteExtender is based, is now part of the AJAX Control Toolkit project. Download it and add a reference to its assembly in your own project(s). (Thank you Dave for reminding me!)

2. In SmartAutoCompleteBehavior.js, go to the end of the file and replace the last line with the following. Note the namespace of the base AutoCompleteBehavior has changed.

i88.UI.SmartAutoCompleteBehavior.registerClass(
'i88.UI.SmartAutoCompleteBehavior',
AjaxControlToolkit.AutoCompleteBehavior);

3. In SmartAutoCompleteExtender.cs, add a using reference to the AjaxControlToolkit namespace.

using AjaxControlToolkit;

4. In SmartAutoCompleteExtender.cs, go to the method GetScriptReferences() and change the first reference line with the following. Note the parameters to the call need to be changed.

references.Add(new ScriptReference(
"AjaxControlToolkit.AutoComplete.AutoCompleteBehavior.js",
"AjaxControlToolkit"));

5. In SmartAutoCompleteExtender.cs, go to the method GetScriptDescriptors() and change the line containing serviceURL to servicePath.

if (!string.IsNullOrEmpty(ServicePath))
{
    sbd.AddProperty("servicePath", ResolveClientUrl(ServicePath));
}

6. In SmartAutoCompleteExtender.cs, go to the method GetScriptDescriptors() and change the line containing completionElementID to completionList.

if (!string.IsNullOrEmpty(CompletionListElementID))
{
    sbd.AddElementProperty("completionList", CompletionListElementID);
}

If you made the necessary reference changes to the new assemblies and updated your Web.config you should be up and running in no time.

Download sample VS2005 SP1 Web Application solution

Read full post...