During a recent optimisation cycle of our Audit Log Viewer (Part of the Muhimbi SharePoint Audit Suite) we noticed the RowLimit property on the SPAuditQuery object. Weird, not sure why we missed this the first time around, but we’ll gladly accept this gift and move on.
The thing is, some of our customers just blindly enable all audit events on all of their site collections and never look back. The record stands, I kid you not, at 848 Million lines of audit data in a single table. As our audit software behaves like a good SharePoint citizen, we access all data through the SharePoint object model and never touch the database directly.
Unfortunately, if a user queries the audit log and removes all filters, the SharePoint object model retrieves all data and happily converts each and every line of audit data into an SPAuditEntry object. This is a relatively slow process that cannot be interrupted and may result in extreme memory and cpu usage.
OK, so back to this shiny RowLimit property. Our log viewer already contained some optimisations to deal with large amounts of data, but being able to set the RowLimit is going to solve the problems of even our most demanding customers….. excellent.
Excellent indeed, everything was working great in our development environment, but during a regression test one of our Test farms was complaining and threw an Exception related to get_RowLimit() not being found…. bugger! We rubbed our eyes, fired up Reflector and compared Microsoft.SharePoint.dll from our Test environment with the one in our Development environment.
As is evident in the screenshot listed above, the version running in our Development environment (on the right) has public members that are not present in the version running in our Test Environment (on the left).
It appears that Microsoft has not documented on which version of the DLL the RowLimit property was introduced (12.0.6219.1000 doesn’t have it, but 12.0.6318.5000 does) so we have decided to detect the availability of the property at runtime to allow our software to auto optimise on systems running the newer version of the DLL.
The code is split up in two methods as the actual line using the RowLimit property cannot be in the same method that is testing its presence. This is related to how .net’s JIT compiler works in the background.
///<summary>
/// Check presence of RowLimit and set the value
///</summary>
///<param name="wssQuery">The query to set the limit on.</param>
We are proud to announce the availability of the SharePoint Audit Suite version 1.1.0.0. Although this version adds a number of new features, the main focus has been on improving existing functionality, fixing bugs and improving scalability.
For those not familiar with the product we recommend reading the original announcement. In summary, the Muhimbi SharePoint Audit Suite is a suite of tools that allow auditing to be enabled automatically on new and existing Site Collections, Audit Logs to be viewed using a user friendly viewer and Auditing to be monitored using an Audit Monitor. The software runs on both WSS 3 as well as MOSS.
The key changes and improvements are as follows:
563
New: Improved Excel Exporter
- Now exports in ExcelML format, compatible with Excel 2002/2007.
- Enables Excel’s Auto filtering by default to allow further filtering.
- Print area automatically updated to fit all audit entries.
- Page layout optimised to make the width of the table fit on a single page
478
New: File Audit Log Viewer - Users with full control access on a list or library should always be allowed to open the audit viewer for individual files.
137
New: Add page to website to describe all audit events and link to it from the GUI.
427
New: Audit Log Viewers - Add Login ID to tooltip when hovering over user’s name.
623
New: Increase number of characters in Description column to 300.
517
Bug Fix: An SPRequest object was not disposed before the end of this thread. This was caused by an undocumented issue of the Site Collection picker. Read this blog posting for details.
475
Bug Fix: File Audit Log Viewer - Cannot view audit entries before file is checked in for the first time.
514
Bug Fix: Farm Audit Settings - It appears that Audit Mask is set multiple times when applying a new one.
We really love these free ‘Web 2.0’ kind of services. You add a line or 2 of pre-generated code to your site and BANG, you got yourself a ‘reteweet button’ (see below) or a full blown user forum. Today we’ll show how to add one of those cool ‘Feedback buttons’ that links to UserVoice’s fancy suggestion box service.
To ensure this new functionality is added to every page in the Site Collection we use our free SharePoint Infuser rather than the Content Editor Web Part. No messing about in SharePoint Designer, modifying Master Pages or dealing with ‘Ghosting’ issues.
As part of this example we will sign up to a free UserVoice account, but if you just want to play around you can use our test account details embedded in the JavaScript code below.
Notice the black feedback button in the left screen and the UserVoice overlay in the right one.
Follow the steps outlined below to integrate UserVoice in your site collection:
Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
In the UserVoice Administration screen, navigate to the ‘Widgets’ tab and copy the JavaScript code to your clipboard. (Or use the demo code at the end of this post)
In your SharePoint Site collection, on the Site Actions / Site Settings screen select Infuse custom content from the Look and Feel column.
Paste the content of your clipboard into Infuser’s code window. If you are using IE then you may want to paste it in WordPad first , otherwise all line breaks are stripped out.
Click the Save button and navigate to any page in the site collection
<script type="text/javascript">
var uservoiceJsHost = ("https:" == document.location.protocol) ?
If you have been a SharePoint developer for more than a day, it will come as no surprise that you need to take great care of manually disposing your objects. Much has been written on this subject, but there are still gaps in the SharePoint Community’s knowledge.
A couple of weeks ago we identified an undocumented requirement to call Dispose() on SPFile streams and today we are documenting a resource leak related to SharePoint’s fancy SiteAdministrationSelector class, which allows users of our Audit Suite to quickly switch between the audit logs for different Site Collections.
During our latest test cycle we were seeing the following line in our SharePoint Trace Logs every time our Audit Log Viewer was invoked, even when the SiteAdministrationSelector was hidden or disabled:
An SPRequest object was not disposed before the end of this thread. To avoid wasting system resources, dispose of this object or its parent (such as an SPSite or SPWeb) as soon as you are done using it. Due to flags specified at object creation, this will not be freed until processed by garbage collection. Allocation Id: {F4F8B307-1F2C-4925-9C23-2A1EBED4B475} To determine where this object was allocated, create a registry key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings. Then create a new DWORD named SPRequestStackTrace with the value 1 under this key."
As we are avid users of SPDisposeCheck we were pretty sure we were not leaking any obvious SPSite or SPWeb resources. We tried explicitly disposing the SiteAdministrationSelector in the OnUnload event, but no luck. After several more, and increasingly desperate, attempts we found out that the object that requires disposing is the CurrentItem property, leaving us with the following OnUnload event.
protectedoverridevoid OnUnload(EventArgs e)
{
try
{
// ** Dispose the selected site in the selector. See bug #373
if(siteCollectionSelector.CurrentItem != null)
siteCollectionSelector.CurrentItem.Dispose();
// ** Dispose our global objects
if (_selectedSite != null && _disposeSelectedSite == true)
_selectedSite.Dispose();
if (_selectedWeb != null && _disposeSelectedWeb == true)
_selectedWeb.Dispose();
}
catch (Exception ex)
{
ExceptionHelper.ProcessException(ex, this);
}
}
Additional topics regarding the prevention of resource leaks in SharePoint are discussed in section 7.11 of our SharePoint development guidelines. Download your free copy here.
At Muhimbi we take great pride in the fact that we actually deal with exceptions properly. And when I say properly I mean Not ignoring them, not letting them bubble to the top and make it the users’ problem, but rather catch them, enrich them, log them, take appropriate action and present the user with a friendly message. Oh… and LOG THEM! See, it is so important I mentioned it twice.
During a recent test cycle of our SharePoint Audit Suite, we noticed the following entry in the Event log. The weird thing is that it only happens if the particular Application page was the first page being requested since the Application Pool was last recycled, and only if that request was made by a non privileged (read not a development I can go anywhere administrator) account.
* Message: The file _app_bin/layouts.sitemap required by XmlSiteMapProvider does not exist.
- Exception: System.InvalidOperationException
- StackTrace: at System.Web.XmlSiteMapProvider.CheckSiteMapFileExists()
at System.Web.XmlSiteMapProvider.GetConfigDocument()
at System.Web.XmlSiteMapProvider.BuildSiteMap()
at Microsoft.SharePoint.Navigation.SPXmlContentMapProvider.BuildSiteMap()
at System.Web.XmlSiteMapProvider.get_RootNode()
at Muhimbi.SharePoint.Audit.AuditLogViewer.provider_SiteMapResolve(Object sender, SiteMapResolveEventArgs e)
Fortunately, and surprisingly, the error message is quite descriptive. Our first hunch was that SharePoint is trying to load ‘_app_bin/layouts.sitemap’ using the current user’s credentials. After the first request is successful it caches the file for future requests, quite sensible.
To prove our hypothesis we fired up our favourite troubleshooting tool, Process Monitor (Thanks Mark!) and placed a filter on the file system to only return entries containing ‘.sitemap’. After making the first request it became clear that SharePoint is indeed using the current user’s account to access this file as is evident in the following screenshot.
The solution, as it so often is, is to elevate the part of the code that causes the sitemap file to be read. in our case the following bit.
///<summary>
/// Event handler that allows the breadcrumb to be modified.
Another day and another cool example of how the SharePoint user interface can be modified using our free SharePoint Infuser. Today we are using some JavaScript magic to make this carpet … errrr … menu float in the same position while scrolling through a page.
To ensure this new functionality is added to every page in the Site Collection we use Infuser rather than the Content Editor Web Part. The JavaScript code is relatively simple, all it does is hook the scroll event, check if the menu is about to scroll off-screen and then re adjust the ‘top’ of the menu with the position of the scroll bar. Some additional code inserts a place holder element in the space that used to be occupied by the menu to ensure the width of this area doesn’t collapse.
There are more elegant ways to achieve floating effects, but the advantage of this code is that it works in IE6,7,8, FireFox, and Google Chrome. (It really works brilliantly in Chrome, as smooth as it gets)
Notice how the Quick Launch menu scrolls with the content
Follow the steps outlined below to implement the changes on your site collection:
Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
From the Site Actions / Site Settings screen, select Infuse custom content in the Look and Feel column.
Copy the script at the end of this posting and paste it into Infuser’s code window. If you are using IE then you may want to paste it in WordPad first , otherwise all line breaks are stripped out.
Click the Save button and navigate to any page that is long enough to have a scroll bar and scroll the window down.
<!-- Load the JQuery Libraries that ship with Infuser -->
Today we are fixing something that has been bothering us for a long time, which is the lack of proper navigation in the SharePoint Wiki, particularly the lack of a ‘home’ button and the fact that the Breadcrumb navigates to allitems.aspx. Grrrrrr.
So, in order to fix this we use SharePoint Infuser to insert the appropriate JavaScript into every Wiki Page in one go. Similar workarounds have been available for a while, but they need to be applied to each wiki page separately, which isn’t a scalable solution.
We are using Chris Chapman’s article on how to add buttons to the Wiki Toolbar as a starting point, we then add some JQuery magic to locate the appropriate breadcrumb link and set its URL to the wiki home page in a way that works across different languages as this page is not always called ‘home.aspx’.
Follow the steps outlined below to implement the changes on your Wiki:
Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
From the Site Actions / Site Settings screen, select Infuse custom content in the Look and Feel column.
Copy the script at the end of this posting and paste it into Infuser’s code window. If you are using IE then you may want to paste it in WordPad first , otherwise all line breaks are stripped out.
Click the Save button and navigate to any Wiki page.
Note that the script below works without modification on a ‘Wiki Page Library’. In order to make it work on a ‘Wiki Site’ change the ‘wikiHome’ variable to ‘../’ or whatever the equivalent of ‘home.aspx’ is in your language.
<!-- Load the JQuery Libraries that ship with Infuser -->