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();

Finding and Removing a Rogue SharePoint Web Config Modification

During development of a small tool to enable binding redirection of .net libraries referenced in a SharePoint site, I found that ApplyWebConfigModifications() calls to the SPWebService were failing due to an existing SPWebConfigModification. The existing modification was atempting to access a path that does not exist in the web.config file.

To find the modification that is failing, I added a breakpoint and whilst debugging opened the following statement in QuickWatch in Visual Studio:

SPFarm.Local.Services.GetValue<SPWebservice>()

Then I navigated through the following properties in the Quick Watch window:
WebApplications/base/base/Non-Public members/BackingList

This offers access to all the web applications on the farm. For each web application under that node, open the WebConfigModifications node and check each one for the path that is reported to be failing. Then you can delete that faulty WebCofigModification using the following code:


        foreach (SPWebApplication thisApp in SPFarm.Local.Services.GetValue<SPWebService>().WebApplications)
        {
            for (int thisApp.WebConfigModifications.Counti > 0i--)
            {
                SPWebConfigModification mod 
thisApp.WebConfigModifications[i - 1];
                if 
(mod.Path.ToLower().Contains("[TEXT IN BAD PATH]"))
                      thisApp.WebConfigModifications.Remove(mod)
;
            
}
            thisApp.Update()
;
        
}


By deleting the faulty modification from the collection, the ApplyWebConfigModifications() call will now run to completion without raising an exception.