Thursday, February 28, 2008

Why Reflector is a Developer's Friend

If you have been wondering why some .net developers rave about Reflector as the one tool that rules them all, and have thought that maybe you should give it a try, here's a little tale about how it made my day better... (hope it encourages you)

Whilst attempting to bind an SPGridView to a LinqDataSource, one of the requirements was to use the filtering features of the SharePoint gridview (that's one of it's strengths above the standard GridView control).

I came across a post by Robert Fridén that described how to enable filtering when binding to an ObjectDataSource. An SPGridView property named FilteredDataSourcePropertyName needs to be set, and that must contain the name of the property on the bound datasource which will be called when filtering the data. In other words, it requires a string containing the name of a control property.

For an ObjectDataSource, that property is named "FilterExpression". I decided it was highly unlikely that the LinqDataSource would use the same property name, so I turned to Reflector.

In Reflector, I found and opened the System.Web.Extensions dll, browsed to the LinqDataSource class and then looked through the properties. Didn't need to right-click and disassemble the dll in this case, as one of the properties was named "Where". Sounded a good option for filtering. So I used that as the FilteredDataSourcePropertyName value, played around a little with the FilteredDataSourcePropertyFormat property of SPGridView, and hey presto the filtering worked. Sure, I could have looked through the MSDN documentation, but with Reflector I can browse inside the methods of the data source class if needed.

If you've not yet delved inside the .Net dlls with Reflector, give it a go. You'll be rewarded!

...and by the way, as tempting as it was I just couldn't bring myself to put the word"best" in the title ;-)

Sunday, February 24, 2008

VMWare Virtual Machine 'Failed to Lock the File'

Scary moment occurred last week when one of my virtual machines failed to start from VMWare Workstation. The reported error was "failed to lock the file". A bit of searching revealed that I needed to delete the .LCK file in the VM's folder.

The cause for this (I think) was that I had opened the virtual disk of this VM as a mapped drive on the host machine (TIP: very useful feature to get at files from the VM without powering it up - just right click on the .VMDK file in Windows Explorere, and you'll see a couple of options there to map the disk as a drive). That drive was still mapped when trying to start the VM, meaning that the host machine was accessing the VM's files.

Thursday, February 14, 2008

Some OWSSVR Parameters are Case-Sensitive

Experimenting with some owssvr URL protocol calls today, and kept getting error pages back when trying to retrieve data from a particular view by specifying a "View" parameter in the querystring

e.g. http://[site url]/_vti_bin/owssvr.dll?CS=109&List={list Guid}&View={View Guid}

Tried swapping various list ids, and removing the view id parameter. Well, it turns out that the View ID is CASE-SENSITIVE, yet the List ID value is not case-sensitive. Cunning way to throw me off the scent, there!

Monday, February 4, 2008

MOSS Search Box Missing Search Scopes

Had a situation where the search box on the SharePoint home page on a MOSS site was missing the "All Sites" and "People" options in the search scope dropdown.

Luckily John M. Cass has posted a fix - if the display group named "Search Dropdown" is missing (you only see the group named "Unused Scopes" on the Search Scopes admin page in the Site Settings), add a new group named "Search Dropdown" and add the two scopes to that group.

Thanks for that, John.

Wednesday, January 30, 2008

Incorrect Alternative Access Mapping Removes Search Scope Options

Experimenting a little with MOSS today, I found that if I set the Alternative Access Mapping of a MOSS site to be incorrect, then the search scope dropdown box in the associated site loses two of the standard search scope options.

After setting the AAM to the wrong value, the dropdown only offers the "This Site:..." option. The "All Sites" and "People" scopes are missing until I correct the AAM value.

Thursday, January 10, 2008

A Wrong (!) Exception Message when Applying SPWebConfigModification

Found that there is an error in an exception message associated with SPWebConfigModifications. The error message I was getting was as follows:

Failed to apply a web.config modification to file "configuration/runtime". The specified node "c:\inetpub\wwwroot\wss\virtualdirectories\100\web.config" was not found in the web.config file.

Just in case I was setting reversed values, I debugged for a while then opened up reflector. Seems that the author of SPWebConfigFileChanges got the parameter order wrong when deriving the exception message in ApplyModificationsWebConfigXmlDocument()!

Adding a BindingRedirect to Web.Config Using SPWebConfigModification

Had a need to remap some DLLs developed for a SharePoint site to different versions of third party libraries (the DLLs had been compiled against other versions of the libraries).

Found that this can be achieved by adding Binding Redirect nodes to the web.config file of the SharePoint web application. Actually getting this to work, however, is not straightforward; the main cause for complexity is that the parent node in the config file (the assemblyBinding node) has it's own namespace. This requires careful Xpath in the SPWebConfigModification name and path values.

Here are the necessary values:

string path "configuration/runtime/*[namespace-uri()='urn:schemas-microsoft-com:asm.v1' and local-name()='assemblyBinding']";

string 
name = string.Format("*[namespace-uri()='urn:schemas-microsoft-com:asm.v1' and local-name()='dependentAssembly']/*[namespace-uri()='urn:schemas-microsoft-com:asm.v1' and local-name()='assemblyIdentity'][@name='{0}']/parent::*", LibraryName);

Use these in conjunction with the following code to create the necessary value to be inserted into the web config file:

string WebConfigElement @"<dependentAssembly>
        <assemblyIdentity name='{0}' publicKeyToken='{1}' culture='neutral' />
        <bindingRedirect oldVersion='{2}' newVersion='{3}' />
      </dependentAssembly>"
;
string 
webConfigValue = string.Format(WebConfigElement, LibraryPublicToken, LibraryName, OldVersion, NewVersion);

Where LibraryPublicToken, LibraryName, OldVersion and NewVersion are the string values to be inserted into the bindingRedirect node that will be added to the web.config.

Set the owner, sequence and type for the SPWebConfigModification, and apply to create the new config file entry:

SPWebConfigModification mod = new SPWebConfigModification(name, path);
mod.Value = webConfigValue;
mod.Owner = string.Format("SetAsposeVersions.{0}", LibraryName);
mod.Sequence = 0;
mod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

webApp.WebConfigModifications.Add(mod);
webApp.Update();
SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();