Let's assume that you have a medium sized SharePoint Server 2007 farm with two WFEs behind an F5 “BIG IP” LTM.
The host name for each configured web application resolves to the Virtual IP (VIP) on the F5, which in turn performs it's sophisticated load balancing function and routes the traffic to one of the two designated WFEs for processing.
Naturally, you would visited F5's web site and followed this deployment guide when creating your configuration profile and HTTP pool. And would assume that all is well, right? Well, mostly, but maybe not...
During testing, you begin to notice that some requests are getting dumped on the HTTP response, which is causing the browser to provide a 404 error. After some investigation, you realize that this abnormality only occurs under very specific, yet obscure, conditions. In my case, I had a custom SharePoint feature which included a WebContol which was loading as a CustomAction in the document library list ViewToolbar. This WebControl performed some configuration settings adjustments similar to those described in my post entitled “Using a Delegate Control Feature to Reconfigure OOTB Site Definitions“. Upon completing the execution of the changes included in my class, I tagged the list to avoid future re-execution of that passage, and performed a page redirect to reload the page so the user would see the new settings.
This is where things got very interesting...
It turns out that I only had the browser 404 when the request traffic was flowing through the F5 LTM. If I set a local host entry on the client, my WebControl would do it's work, reload the page, and everything was just fine. Even more perplexing was the fact that with the custom feature de-activated, initial list library loads flowing through the F5 occurred without error as well. Very strange indeed...
So, a few fine colleagues and I began the lengthy process of sniffing the traffic using Net Mon on both the client and the server in order to find out exactly what was happening. What we found was both slightly confusing, and very unexpected. To set this up, let's go back to the F5 Deployment guide I referenced earlier. In section 1-8, the guide lays out the steps for creating the HTTP pool. Step 6 states:
6. In the Settings section, check the Custom box for Redirect Rewrite, and from the Redirect Rewrite list, select Matching.
Well, it turns out that Redirect Rewrite is an interesting little feature indeed. SOL9612 on the F5 support site (requires registration) describes the specifics of this setting, which is so quickly passed over in the deployment guide it isn't even funny.
Basically, when a requested URI does not include a trailing slash (a forward slash, such as /, at the end of the URI), some web servers generate a courtesy redirect. That sounds like an OK thing, right? Sure, but guess what, and this is the “Gottcha“...
In BIG-IP LTM version 9.x you can configure an HTTP profile to rewrite URLs so that redirects from an HTTP server specify the HTTPS protocol.
Whoa, what just a minute! That doesn't even sound like the same feature. how did we go from slashes to protocol redirection. Hmmmm.... As it turns out, the Redirect Rewrite options available are as follows:
-
Choose All to rewrite any HTTP 301, 302, 303, 305, or 307 redirects to HTTPS
-
Choose Matching to rewrite redirects when the path and query URI components of the request and the redirect are identical (except for the trailing slash)
-
Choose Node to rewrite redirects when the redirect URI contains a node IP address instead of a host name, and you want the system to change it to the virtual server address
So, basically, if we follow the settings recommendations included within the deployment guide referenced above, we inadvertently setup the F5 in such a way that any redirect with a matching referrer, such as the one I had placed in my WebControl, will cause the HTTP response coming from the WFE to be rewritten by the F5 as an HTTPS response... as a courtesy, of course :)
Ok, back to the deployment guide one more time... Above the step by step in section 1-8, there is a short disclaimer as well as a note written in italics. These state the following:
Important:
If you are using the WebAccelerator module, we recommend you configure an HTTP profile based off of the default HTTP profile, and only change the Redirect Rewrite option to Match. Any other settings in this case are optional.
-and-
The following procedure shows one way to optimize the Microsoft SharePoint 2007 configuration that has been tested in real-world scenarios by F5, and shown to give the greatest improvement. These procedures and the specific values given in some steps should be used as guidelines, modify them as applicable to your configuration.
So, what the fine print is really saying here is:
- If we are using the WebAccelerator module, we should NOT set the Redirect Rewrite options to Matching, but rather set it to Match, which interestingly enough is not a listed option in the above referenced support article on the F5 support site, nor (as is the case with all the options for this setting) is it listed or explained anywhere in the deployment guide.
- These settings, including step 6, and their specific recommended values should be used (only) as guidelines, and may require modification in your environment.
Well, in the case of a SharePoint implementation, while I can see some value in the whole trailing slash detection thing, I can't see many cases where I would want HTTP traffic being converted into HTTPS traffic, at least not in this case. Upon changing the Redirect Rewrite setting to None, everything works fine again and the browser errors disappear (magic!).
On a side note, I think it is worth mentioning that if you are doing development of custom components for your SharePoint implementation, and you plan on using an F5 LTM, you might want to avoid performing redirects, especially in cases where you are simply trying to reload the current page for the user. Although, hopefully you find this post first, and simply adjust the settings to resolve the issue entirely.
-Mark
Please feel free to send any thoughts, comments, or questions to mark@solutionsmark.com
Scenario:
Let’s assume you needed every team site in your SharePoint Server 2007 environment to have some settings set a certain way, be branded, and have some web parts moved around on the default page. Well, traditionally speaking, you had the following supported options:
1.) Feature Staple in some new custom features (which alone, doesn’t really solve your web part objective)
2.) Copy the STS site definition and use it as the basis for your own new custom site definition
3.) Create a new site template for use (which precludes your users from creating a site template of their own in the future)
Each of these options poses some upgradability issues, but none more than the one that most optimally meets your objectives, the custom site definition.
What if you could simply use the OOTB team site definition, which is easily upgradable, reliable, and template-able, but you could still meet each of your objectives, and as a bonus you could even manage the state of configuration over time and apply updates as desired.
The goal of this post is to guide you through the creation of a SharePoint Feature which will provide the following functionality:
1. Loads a new control on every page without the need for customization of the default.master or application.master
2. Eliminates the need for a Custom Site Definition by allowing you to perform all the required changes at runtime, starting from an OOTB Site Definition
3. Tags a site or list library with the version of the changes applied so as to prevent the actions from being re-performed on every page load
4. Allows for the rolling update of site and list library settings/configurations over time without the need to re-provision sites and without disturbing existing content (unless intended)
We are going to accomplish all of these objectives without:
1. Creating a Custom Site Definition
2. Changing any XML Definition files on the server over time
3. Breaking any of the supportability guidelines established by Microsoft
4. Creating the additional difficulty associated with Custom Site and List Definitions during upgrade
The key to achieving our goal is the use of assembly based configuration management, which is basically performing your changes through code, via the object model, and tracking the change sets applied to a given object. Sounds easy, right? Well, it is actually, and I’m about to show you how!
Before we get started, lets layout the basic principals which make this approach work within SharePoint:
1. SharePoint has a rich object model which allows you to perform almost all of the changes required, so it’s fairly straightforward to apply the needed changes via code.
2. SharePoint’s object model, specifically key objects, contain PropertyBags (or hashtables), which are stored on the object as an array of named Key/Value pairs . This is important, because Microsoft put these here for extensibility so developers can store and persist information needed by components at runtime.
3. SharePoint’s Control Feature Element type allows for use to assign a delegate control which can load on every page in SharePoint as an additional control, which allows us to easily bind the firing of our code into the execution pipeline. (more on this in a bit, this is a key piece of the secret sauce of this solution)
4. SharePoint’s FeatureSiteTemplateAssociation Element type allows for the assignment of added features to be activated upon site creation when sites are created using the specified site definition, in this case the OOTB site definitions.
Alright, so let’s layout how this approach actually performs the changes at runtime. On every page that loads, there is a delegate control called “AdditionalPageHead”. This control is an array control, which allows for multiple instances. This allows for us to have our custom control load alongside the OOTB control. This control is key to our approach because it is within this control that we will use code to perform the configurations changes required.
I know what you are thinking… You want to know if we perform the changes using code on every page load, wouldn’t that slow down things for the user? We wouldn’t want to execute these actions every time the page loads, right?
Right! This is where the PropertyBag enters the picture. Once we have executed our changes, we will add a new key to the PropertyBag of target object. We will have the code that performs the changes check for the existence of this key before it executes our changes. The result is that the code performed changes occur during the very first user request, after which the key is detected pre-venting subsequent loads from re-performing the changes.
Let’s take it even one step further. Let’s say the value of the key we place in the object PropertyBag contains the version of the changes we are applying. Ah-Ha! This allows us to deploy an updated assembly with addition changes at a later time. When this assembly loads with the first user request, it will check for key and find that it is out of date, upon which it will execute the outstanding change sets needed to bring the key version current.
Right on! So what sorts of changes might we want to execute? We could:
- Remove a sub-site that comes with the OOTB definitions (such as “Report Center” in a Collaboration Portal)
- Change around web parts on the main page of the definition
- Create or drop lists, rename lists, etc.
So, why not just use a feature event receiver to do these things? Very good question! You could for some of these things, but in the case of web part changes, page changes, or updates to the provisioned sub-sites in a publishing site, feature events are all firing crazy during creation, making it hard to know for sure that the page on which you want to make the changes even exists yet. Often times, the Microsoft internal provisioning handlers are firing in order to lay down the assets for a specific functionality, which you need to change in some way. That’s why we need to let all of that occur during site creation, and perform our changes during the first user request load. Also, when using feature events, in order to apply updates to the changes, we need to re-activate the feature on every existing site we have, where as this approach allows for farm wide changes to be affected, in addition to allowing for the management of changes over time, even if the control feature is scoped at the site level.
When using this approach, the very first load might take a few more moments, but subsequent loads are not delayed by the single action of checking for the key and then dropping out of execution. Because the changes are performed using elevated privileges, the user making the request is not important, and with the very last action performed being a simple refresh of the page, the initial user is unlikely to even notice that anything even happened, since the first time the see the site rendered, everything has already been changed as required.
Because we are using a feature stapler to bind our control to an OOTB site definition, we need not create our own. Once the control is in place, it will perform our change sets as required upon each deployed update of the control assembly, which is completely supported during the update of a SharePoint Solution. We use a good old case statement to make sure we perform our change sets in order without skipping any of them as we bring an object current.
Download Sample Visual Studio Project
Please feel free to send any thoughts, comments, or questions to mark@solutionsmark.com
A special Thanks goes out to Subbu (Subramanian S) for his contributions to this post, both in code/collatoral and in conversation...
More to come!
Let me begin by introducing myself...
My name is Mark Ferraz. I am a Information Architect specializing in SharePoint Products and Technologies. I am based out of Houston, TX, and am principal of a Houston based consulting firm, SolutionsMark. Currently, I am the Solutions Delivery Build Lead for the GIL 3 Information Management project at Chevron, one of the largest entirely SharePoint based solutions ever. I've been working with Bill, Ben, Mark, and others on Ben's upcoming Best Practices book on Enterprise SharePoint Deployments as a contributing author. My background in IT spans over 10 years of service, mostly Microsoft, ranging from ERP (Great Plains) to CRM, SharePoint (IW Solutions), backend Infrastructure and supporting networks, as well as heads down custom development and integration. Today, I am an architect first, a sub-team lead second, and I thoroughly enjoy stepping down into the code (C#/VB/SQL/Whatever) and getting my hands dirty or even owning a minor feature. I'm a teacher in that I coach my team members to become better consultants, developers, and representatives of Microsoft technologies.
I'm looking forward to contributing to the Mindsharp blog roll, by bringing my real world experience from the front lines, as well as my occasional personal and professional thoughts and commentary. I hope you as the reader enjoy my posts, and I appreciate any and all feedback and or comments you might provide. Thanks in advance!