Simplify Your Caching By Using a Generic Method

I needed to add caching to my data access routines to improve the performance of commonly accessed data.  This is pretty straightforward:

  • Check to see if the cache entry already exists
  • If the cache entry does exist, return the cached value
  • If the cached entry doesn’t exist, fetch the data and add it to the cache.

The problem was, I had a lot of data access routines that I wanted to add caching to.  Adding the 4 or 5 lines of code needed to do this to each routine would be tedious, and all of the repetition would be messy.  I knew I had to centralize my caching functionality in one place.  Since my data access routines returned many different types, I decided to use a generic method to perform the caching.  Since the data validation routines essentially had to be wrapped by this function (so that it’s only run if the value doesn’t exist in the cache), I call it using a statement lambda.

Here’s what I came up with:
//I use ASP.Net's cache object.  I get a reference to it with System.Web.HttpRuntime.Cache
//as I won't always be using it in the context of ASP.Net
private static System.Web.Caching.Cache DataCache = System.Web.HttpRuntime.Cache;

public static T CacheFetch<T>(string key, Func<T> fetcher) where T:class
{
	//Don't bother with the caching if the key is null or blank
	if ((key ?? "").Length <= 0)
	{
		return fetcher();
	}

	T result = DataCache[key] as T;

	if (result == null)
	{
		result = fetcher();

		if (result == null)
		{
			DataCache.Remove(key);
		}
		else
		{
			DataCache[key] = result;
		}
	}

	return result;
}

And here’s some examples of how I used it:

Original data access routine:
public static IEnumerable<Trustee> GetTrustees(int infoReturnID)
{
	InfoReturnEntities context = new InfoReturnEntities(new Uri(Common.InfoReturnDataServiceURL));

	IEnumerable<Trustee> trustees = from trustee in context.Trustees
									where trustee.InfoReturnID == infoReturnID
									select trustee;

	return trustees;
}
Updated data access routine:
public static IEnumerable<Trustee> GetTrustees(int infoReturnID)
{
	return Common.CacheFetch<IEnumerable<Trustee>>("Trustees_" + infoReturnID.ToString(), () =>
	{
		InfoReturnEntities context = new InfoReturnEntities(new Uri(Common.InfoReturnDataServiceURL));

		IEnumerable<Trustee> trustees = from trustee in context.Trustees
										where trustee.InfoReturnID == infoReturnID
										select trustee;

		return trustees;
	});
}
And another example:
public static IEnumerable<RevenueRange> GetRevenueRanges()
{
	return Common.CacheFetch<IEnumerable<RevenueRange>>("RevenueRanges", () => {
		InfoReturnEntities context = new InfoReturnEntities(new Uri(Common.InfoReturnDataServiceURL));

		IEnumerable<RevenueRange> revenueRanges = from e in context.RevenueRanges
												  where e.RevenueRangeCD != "?"
												  orderby e.LowerLimit
												  select e;

		return revenueRanges;
	});
}

My method was inspired by this.

Performance Profiling a SharePoint 2010 Project using EQATEC Profiler

I wanted to profile a SharePoint 2010 project i’d been working on, in order to find some of the slower methods so that they could be improved.  I decided to give EQATEC Profiler a try since it had some good recommendations on StackOverflow and was FREE.

EQATEC works by modifying and rebuilding your assemblies.  Since I use Visual Studio 2010’s built in package and deployment features, it needs to be run after the build, but before the project is packaged and deployed to the SharePoint server.

Here’s how I got it working:

  1. Start EQATEC Profiler. Under ‘Application to profile’ select your project’s bin\debug folder. Check-mark all of the assembly’s you would like to profile.
  2. Click ‘Build’.  This will rebuild the project with added profiling bits, as well as add ‘app.eqconfig’ and ‘EQATEC.Profiler.RuntimeFullNet.dll’ to your output folder.
  3.  The EQATEC assembly needs to be added to your project’s package for it to function properly.
    • Open your project in Visual Studio 2010.
    • Open your project’s package and click on the ‘Advanced’ tab.
    • Click ‘Add’ -> ‘Add Existing Assembly…’. Browse and select ‘EQATEC.Profiler.RuntimeFullNet.dll’ from your bin\debug folder.
    • You can leave the default location and selection of ‘Global Assembly Cache’.
    • Click OK.
    • Save the package.



  4. Open the project properties and select the ‘Build Events’ tab.  Add the following command to the Post-Build Commands:
    "C:\Program Files (x86)\EQATEC\EQATECProfiler\EQATECProfilerCmd" -build app.eqconfig

    This will cause your assemblies to be recompiled with EQATEC once the standard build is done.

  5. Deploy your project to SharePoint.
  6. Exercise your project in SharePoint.
  7. In EQATEC, click on the Run tab.  You should see messages that your profiled application has started.
  8. Once SharePoint has “warmed up” and your project is performing normally, click the ‘Reset Counters’ button in EQATEC.  This will reset the profiling so that you can begin collecting data.
  9. Exercise your project in SharePoint. Make sure you exercise all code you’d like profiled.
  10. Back in EQATEC, click the ‘Take Snapshot’ button.  This will create a report of your profiling session.
  11. Under ‘View snapshot reports’ double-click on the report you’d like to view.  This will open the view tab, where you can explore the results of your profiling session and find the slower methods in your project.
  12. Don’t forget when you’re done profiling to remove the EQATEC assembly from your package as well as remove the post-build step.  Leaving them in will decrease your project’s performance.

Search Refinement Panel Web Part “Show More” Link Not Working

I recently discovered that the “Show More” link on the Search Refinement Panel web part had stopped working, seemingly out of the blue.  With a bit of debugging I discovered that the functions defined in the onclick event:


onclick="SearchEnsureSOD();ToggleRefMoreLessFilters(this, true);"

were returning “Object Expected”.  For some reason the functions were no longer defined.

I eventually figured out that the problem was that I had removed the Search Box web part from the page and replaced it with my own custom search box.  Apparently the Search Box web part is required on the same page as the Refinement Panel web part, as it injects JavaScript into the page that is used by the Refinement Panel.  I fixed the problem by adding the Search Box web part back onto the page and hiding it.

Deploying Localized Satellite Assemblies with SharePoint 2010

Localizing web parts in a SharePoint 2010 project is pretty straight forward. Add resource files to your project, set the Deployment Type to AppGlobalResource, and then access them with GetGlobalResourceObject or with the <%$Resources> tag. Unfortunately this only works where you have the HttpContext – so great for web parts, but useless for Timer jobs and event receivers.

In order to access the localized resources when there is no HttpContext you’ll need to access the embedded resource files.  If the resource file build action is “Embedded Resource”, Visual Studio will generate a satellite assembly for each locale that you have a resource file for. If you check your build output folder, you should see something like this:

MyProject.dll Main assembly
fr-FR\MyProject.resources.dll Satellite Assembly
en-US\MyProject.resources.dll Satellite Assembly

Great! So now that we have the resources embedded in our satellite assemblies, we can just access them with Resources.MyResource.Key or ResourceManager.GetString, right? That’s what I thought, but whenever I went to retrieve the resource i’d only ever get the default value, i’d never get the localized value.  After snooping through the WSP file I realized that although the satellite assemblies are built automatically, they are not automatically packaged in the WSP.

In order to access the localized resources, the satellite assemblies need to be manually added to the package:

  1. Open the Package in the SharePoint solution
  2. Select the Advanced Tab
  3. Click Add and select Add Existing Assembly… (Add Existing Assembly from Project Output… does not work)
  4. For the Source Path find and select the satellite assembly you’d like to add
  5. Leave the Deployment Target set to Global Assembly Cache
  6. The location will be automatically set to the name of your satellite assembly.  The locale folder needs to be appended to the location name. For example the fr-FR satellite assembly would read fr-FR\MyProject.resources.dll.
    Adding Satellite Assembly
  7. Click OK (Safe Controls and Satellite Resources do not need to be added)
    Satellite Assembly Added
  8. Repeat for each Satellite Assembly in your project

After deploying the modified package, you should now be able to access your localized resources.

Gotchas

One problem with this solution is that the path to the satellite assemblies is hard coded. So when you switch from a Debug to Release configuration (or vice-versa), you now have to modify each of the satellite assembly entries to point to the new location. Microsoft suggests that if you will be changing configurations often, you should add a post-build step that copies all of the satellite assemblies to a specified folder and then references that copy of the assemblies in the package.

More Info

http://msdn.microsoft.com/en-us/library/gg615453.aspx

SharePoint 2010 FBA Pack Hits #3 in Popular Releases on CodePlex

I was pleased to discover today that the SharePoint 2010 FBA Pack is in the 3rd spot for popular releases for the week on the CodePlex home page.  It’s nice to see that the SharePoint community is making use of it.

SharePoint 2010 FBA Pack Popular Release On CodePlex

http://sharepoint2010fba.codeplex.com/

SharePoint 2010 FBA Pack Released

I’ve just released the SharePoint 2010 FBA Pack on CodePlex:

http://sharepoint2010fba.codeplex.com/

The FBA Pack is a collection of web parts and tools for managing forms based authentication in SharePoint 2010.  It is a port of the SharePoint 2007 CKS Forms Based Authentication Solution to SharePoint 2010.  It has been changed extensively to work with SharePoint 2010’s claims based authentication and has been restructured to use Visual Studio 2010’s new SharePoint project type.

SharePoint 2010 can be configured out of the box to authenticate against an ASP.NET Membership database, but strangely it does not include any tools for managing membership users and roles, or any web parts to allow new users to register or to change/reset their password.  That’s where the FBA Pack comes in – it contains:

User Management

Users can be created, deleted and edited, as well as assigned to Roles or SharePoint groups.

Manage Users Page

Manage Users Page

Role Management

Roles can be created and deleted.

Manage Roles Page

Manage Roles Page

Change Password Web Part and Page

This highly configurable web part will allow a user to change their password.  Additionally a built in Change Password page has been included, with a link to it on the users menu.

Change Password Page

Change Password Page

Membership Request Web Part

This highly configurable web part will allow new users to register to site.  An email will be sent to the user with their temporary password and instructions to login to the site.  As well there is the option to review membership requests.

Membership Request Web Part

Membership Request Web Part

Password Recovery Web Part

This highly configurable web part will allow a user to reset their password.  An email will be sent to he user with their temporary password and instructions on changing it.

Password Recovery Web Part

Password Recovery Web Part

Membership Review List

The FBA Pack can be configured to allow new user requests to be moderated.  The membership review list displays all new membership requests, which can either be accepted or rejected.

Membership Review Page

Membership Review Page

Use JPEG’s in Reporting Services if exporting to PDF

I recently made the mistake of using PNG’s for high-resolution background images in SQL Server Reporting Services (2008 R2). I wanted to use PNG’s as they were lossless, supported alpha transparency and actually generated smaller files than JPEG for the images I was using.  Unfortunately I ran into these problems when exporting to PDF:

SLOW export to PDF
PNG exported to PDF: 17 seconds.
JPEG exported to PDF: 2 seconds.
GIF’s also take the same ridiculously long amount of time as PNG’s to export to PDF.

No Alpha Transparency Support
I was initially planning to have a “DRAFT” watermark appear on the report based on a parameter.  I thought an easy way to do that would be to add a PNG with alpha transparency as an additional image object, and show/hide it as needed. This works great when exporting the report to a TIFF file, but it turns out the PDF renderer does not support transparency:

Alpha transparency exported to TIFF

Alpha transparency exported to TIFF

Alpha transparency exported to PDF

Alpha transparency exported to PDF

I finally concluded that JPEG’s are the only option if the report is going to be exported to PDF. In order to solve my DRAFT watermark issue, I ended up having to create two versions of each image, one with a draft watermark, one without.