Archive for the ‘Developer’ Category

Managing Customizations to ASP.NET & SharePoint Browser Definitions

Wednesday, November 2nd, 2011

This article’s purpose is to discuss the best practices around managing customizations to ASP.NET’s Browser Definitions. For more details around ASP.NET’s browser definition platform, please see the Browser Definition File Schema (browsers element) article on MSDN. A quick overview of ASP.NET Browser Definitions can be found in the side panel.

ASP.NET Browser Definition Overivew
In any IIS site, including SharePoint sites, Microsoft provides a highly configurable platform for defining the various capabilities and mobile adapters of a browser. To facilitate this, Microsoft uses what is called a Browser Definition File which is an XML-based file that defines browsers, what makes that browsers different from the rest (the Identification), and browser properties – capabilities and mobile adapters. Microsoft provides several definition files out-of-the-box with ASP.NET that define various browsers. Then, individual web applications can provide their own Browser Definition Files that will supplement or override the out-of-the-box files. ASP.NET uses this information to tailor page rendering based on the browser making the page request.

ASP.NET allows for multiple files that all have the same schema. There are two sets of files that ASP.NET parses:

  1. Predefined Browser Definition Files – This set of files is specific to the version of the .NET Framework being used in the web application and contains the out-of-the-box ASP.NET browser definition files.
    %SystemRoot%\Microsoft.NET\Framework\
      version\CONFIG\Browsers
  2. Application-Level Browser Definition Files – This set of files is specific to each web application and contains the web application specific browser definition files.
    App_Browsers directory within the web application’s web root folder (e.g. inetpub or inetpub\wss\VirtualDirectories\80)

Each individual browser is defined using a <browser> tag. Within this tag, there are several other allowed tags that define how a browser is uniquely identified and what unique attributes should be defined for that browser. Browser definitions follow an inheritance hierarchy. New definitions must define a parent definition or existing definitions can be modified using the definition’s ID.

ASP.NET loads each browser definition file by concatenating them – each browser file contains a series of browser tags. The predefined files are processed first based on the ASP.NET version being used followed by the application-level files. Within each file location, ASP.NET seemingly processes each file in alphabetical order by file name. This means that if there are multiple definitions for the same browser, it seems that the definition in the last file will take precedence.

SharePoint chose to implement two browser definition files that are deployed locally to each SharePoint web application’s App_Browsers directory. This is important as SharePoint deploys its custom browser definitions in the same way that other applications using SharePoint or ASP.NET should deploy them – as separate .browser files deployed to the application-level App_Browsers directory. These two files, which may look familiar, are:

  • compat.browser, and
  • compat.moss.browser (If using SharePoint Server editions)

As the Browser Definition File Schema article in MSDN stresses, the predefined files that ship with the .NET Framework should never be modified – ever! This is because they could be overwritten by updates, patches, or service packs; causing any customizations to be lost.

As an extension to this rule, never modify the application-level browser definition files that ship with SharePoint. Why? The same reason as with the predefined files. Future SharePoint updates, patches, or service packs could overwrite these files; causing any customizations to be lost.

So what is left if customizations are required? Thanks to the architecture of these browser definition files, Microsoft allows an application to define its own browser definition files. This is relatively straightforward, but it does require knowledge of the browser definition files you will be overriding. I will cover three scenarios:

  1. Adding an entirely new browser definition
  2. Appending information to an existing browser definition
  3. Modifying an existing browser definition

As far as I know, there is no way to remove a browser definition. However, I’m not sure there would be a need or desire to do so.

Adding an entirely new browser definition
To add a new browser definition, add the definition’s browser element to a new browser definition file. Deploy this file locally into each web application’s App_Browsers folder. This new file’s definition(s) will be combined with the other predefined and application-level definitions.

Appending information to an existing browser definition
To append capabilities, mobile adapters, or other information to an existing browser definition, add a new browser tag to a new browser definition file that uses refID to reference the existing browser’s ID. Add the new information within this browser tag. This definition will be combined with the existing browser’s definition, which could be in another file, and append the new information.

Modifying an existing browser definition
To modify a capability, mobile adapter, or other information already defined as part of an existing browser definition, there are a few options. The first would be to use a similar process to appending information. It is possible to define browser definitions in a new file, using refID to reference the existing browser’s ID, and define the same information with different values. The second would be to implement a new browser, with no additional identification, with the parent browser set to the browser that should be modified.

For example, if the IE browser should be modified to be treated as a mobile device, then the following browser definitions could be used:

  • Option 1:
    <browser refID="ie">
        <capabilities>
            <capability name="isMobileDevice" value="true" />
        </capabilities>
    </browser>
  • Option 2:
    <browser id="ieMobile" parentID="ie">
        <capabilities>
            <capability name="isMobileDevice" value="true" />
        </capabilities>
    </browser>

However, note that if multiple browser definitions exist that reference the same browser ID and each has a different definition of the same information, then the last definition in the last file alphabetically in the application-level will be used.

For example, assume Option 1 was implemented in both MyApp1.browser & MyApp2.browser and that each of those browser files was deployed to the application-level App_Browsers folder. MyApp1 defines IsMobileDevice=True and MyApp2 defines IsMobileDevice=False. Since MyApp2 comes last alphabetically, it will take precedence and IsMobileDevice will be False. This underscores the need for applications to consider the environment’s existing customizations when developing custom browser definitions. In this example, the MyApp2 team, presumably deploying after MyApp1, should have seen MyApp1’s existing customization and implemented a new child browser (Option 2) to avoid a conflict or change MyApp1’s customization. The MyApp2 team would need to be aware that either way that is chosen for implementation will affect the entire web application, so they should consult the MyApp1 team!

Summary
To properly manage customizations to the browser definitions that ship with ASP.NET and SharePoint, applications being deployed to a SharePoint environment should make use of their own browser definition files that are deployed to the application-level App_Browsers folder. However, if the environment is planning on host multiple sets of customizations or applications that will require changes to the browser definitions, I would encourage a single file for each web application to ensure that applications changes are developed properly and do not conflict with each other.

Never modify any browser definition file not directly managed by the application being deployed. To implement the changes to existing browsers within the application browser definition files, it is best to use the refID attribute of the browser tag.

When deploying, changes to the App_Browsers folder should automatically be picked up by IIS and not require any sort of application pool recycle or IISReset.

Finding Sites with a Particular Feature Activated

Saturday, February 12th, 2011

I continually have a question arise that seems easy to answer, yet from what I can tell, is not yet available with SharePoint out-of-the-box in its user interfaces. That question is:

What are all of the sites with feature xyz enabled?

A few years ago with a MOSS 2007 client environment where I had to answer this question, I was left with writing a quick C# console application that would crawl a web application for me and discover all of the site collections with a particular feature enabled. Not quite the best way of doing things, but it’s what was the best at the time.

Fast forward to SharePoint 2010. Now, PowerShell is in the mix and required for all SharePoint installations. Thanks Microsoft! So now, I have the vast capabilities of PowerShell available on any SharePoint farm I may encounter on any client environment with which I may be working. Plus, there’s an added bonus that, for some reason, the word “script” seems to scare clients and IT departments less than “console applications”. Even though PowerShell scripting can often wield the same powers as a C# console application, it seems to be accepted with more ease which makes my life easier.

Now that PowerShell is widely available, I rewrote that “quick C# console application” I referenced above in PowerShell for use recently on a SharePoint 2010 environment. The script below has a slightly more specific task than solving the question I posed above:

Output all of the site collection URLs within a particular web application that have a particular site-scoped feature enabled.

Here’s my script to do just such a task. The code below is meant for a single ps1 file.

Please note that it should work with both the 2007 & 2010 SharePoint product lines: SharePoint 2010 (Foundation & Server), WSS 3.0, and MOSS 2007. I have only tested this code on a SharePoint Server 2010 environment, but have no reason to believe it wouldn’t work in the other environments.

Feel free to use this script or modify it to fit your needs. There are several extra features that could be added to this script to make it even more versatile:

  • Reporting on the status of multiple features, not just a single feature
  • Reporting based on feature name versus feature GUID
  • Reporting on features scoped at different levels besides Site
    • Farm
    • Web Application
    • Web
  • Crawling other scopes besides a single web application
    • The entire farm,
    • Multiple web applications,
    • A subset of site collections,
    • A subset of sites,
    • Based on another block of script and/or function call to determine if a site should be scanned by the script,
    • etc.

I think the above script is a great starting point. Hopefully either myself or someone will get around to adding the above suggestions. Please share in the comments if you do end up extending this script!

Hiding the SharePoint 2010 Ribbon for Readers – A Proof of Concept

Saturday, February 5th, 2011

In SharePoint 2010 publishing sites, the ribbon is the new way of life for authors. However for readers, the ribbon provides very little, if any, functionality. A few days ago, I was asked about hiding this empty space by a client. Their current 2010 master page had the ribbon moved to a custom position on their publishing sites. They had also suppressed the breadcrumb/folder navigation in the ribbon; thus for a typical reader view, there was no ribbon contents that would be displayed. However, the space on the page where the ribbon would live for authors still remained as empty space!

We very well could have developed some server-side logic to determine the permissions of the user and hide that area completely based on that. Given infinite time and resources, I probably would have opted for that solution.

However, several of us were tasked with coming up with an easier and simpler solution to implement. One of the other consultants in the room at the time suggested a solution using JavaScript to hide the area if no contents was found (i.e. if the ribbon hadn’t rendered anything for the reader). I thought it was a great idea and immediately opened up an out-of-the-box publishing site in SharePoint Designer to tinker and develop a bit of JavaScript.

The goal of my JavaScript POC was to hide the entire div tag containing the SharePoint out-of-the-box ribbon control. I investigated and discovered that, in the nightandday.master file, the ribbon is contained in a div with the ID s4-ribbonrow. With that ID, I would be able to hide that div based on its rendered HTML contents. I figured, for this example, that the existence of the text “Browse” would be enough to determine whether or not the ribbon had rendered something or not.

To do this, I added JavaScript code to nightandday.master and it worked like a charm. Below is the relevant excerpt of nightandday.master:

<div id="s4-ribbonrow" ...>
    <!-- SharePoint out-of-the-box Ribbon Controls & Code goes here -->
</div>
<script type="text/javascript">
    var ribbonRow = document.getElementById("s4-ribbonrow");
    if(ribbonRow.innerHTML.indexOf("Browse") == -1)
    {
        ribbonRow.style.display = "none";
    }
</script>

I should note that I only was able to spend about 30 minutes on this entire topic. Please treat the above code as a proof-of-concept and make sure to evaluate the impact or effectiveness of this code in your own environment before using it.