Category Archives: Sharepoint

Trying to use Azure Shared Caching Session State with SharePoint 2010?

Well, don’t. The Microsoft.Web.DistributedCache .dll requires .NET 4.0, which doesn’t work with SharePoint 2010. The fact that 4.0 is required for Microsoft.Web.DistributedCache is nicely buried in this thread, not in MSDN where it would have been, you know, helpful.

Session State running in SQLServer mode works fine still, though.

Let me know if I’m wrong, and also if anyone’s tried the Table Storage provider / whether that has any dependencies on .Net 4.0!

Pro-Tip: Setting FBA Timeout When Using Claims Based Auth in SP2010

If you’re using claims based authentication in SharePoint 2010 and wondering why your Forms Based Authentication claims aren’t reading your web.config timeout=”x” values, it turns out that this is because they’re managed on a different level by the Secure Token Service.

The default timeout seems to be 10 hours (which seems a little excessive for most purposes) but you can change this easily via the SharePoint Powershell console:

[sourcecode]
$sts = Get-SPSecurityTokenServiceConfig
$sts.WindowsTokenLifetime = (New-TimeSpan -Minutes 20)
$sts.FormsTokenLifetime = (New-TimeSpan -Minutes 20)
$sts.Update()
iisreset
[/sourcecode]

This works for both SharePoint Foundation and full SharePoint Server 2010 – thanks to this forum post for the information!

ASP.NET Javascript DoPostBack and SharePoint: Single Postback Issue

Here’s a quick tip (man, there sure has been a lot of SharePoint in my last few posts!)

If you’ve got a Sharepoint page, and normal postbacks (like paging in your SPGridView or LinkButtons) stop working after you use a __doPostBack() javascript command, try adding the two settings just before your postback:

[sourcecode language="javascript"]

_spFormOnSubmitCalled = false;
_spSuppressFormOnSubmitWrapper=true;
__doPostBack(‘eventtarget’, arguments);

[/sourcecode]

Apparently, SharePoint does some viewstate / time / validation / checking which needs to be turned off to prevent your page from dying. I’m sure someone has a much clearer explanation for this out there, for which I’d love to hear – in any case, this fixed my issue so if you’re only having one postback going through on your SharePoint page, this is worth a shot!

Using SPGridView With DataPager (For Nicer Pagination)

Surprise, surprise – another post about SPGridView. This time, we’re looking at how to use the nice .NET 3.5 DataPager control with SPGridView. Out of the box, they don’t work together (for the same reason GridView and DataPager don’t), because SPGridView doesn’t implement the IPageableItemContainer interface, which the DataPager expects.

Lucky for us, someone’s already done all the hard work and thinking in how to extend GridView to implement this interface; the best post I found was this one by Matt which explains the required steps and rationale behind the code very well – I won’t repeat it here.

Unfortunately for us though, the link to download the sample code is broken – but with the magic of the internet, I present to you the code below.

[sourcecode language="c-sharp"]
public class CustomSPGridView : SPGridView, IPageableItemContainer
{
//extending SPGridView to support DataPager controls. see
//http://mattberseth.com/blog/2008/04/using_a_datapager_with_the_gri.html

int IPageableItemContainer.MaximumRows
{
get { return this.PageSize; }
}

void IPageableItemContainer.SetPageProperties(int startRowIndex, int maximumRows, bool databind)
{
int newPageIndex = (startRowIndex / maximumRows);

this.PageSize = maximumRows; if (this.PageIndex != newPageIndex)
{
bool isCanceled = false;

if (databind)
{
// create the event args and raise the event

GridViewPageEventArgs args = new GridViewPageEventArgs(newPageIndex); this.OnPageIndexChanging(args);
isCanceled = args.Cancel;

newPageIndex = args.NewPageIndex;
}

// if the event wasn’t cancelled
// go ahead and change the paging values
if (!isCanceled)
{
this.PageIndex = newPageIndex; if (databind)
{
this.OnPageIndexChanged(EventArgs.Empty);
}
}

if (databind)
{
this.RequiresDataBinding = true;
}
}
}

private static readonly object EventTotalRowCountAvailable = new object();

int IPageableItemContainer.StartRowIndex
{
get { return this.PageSize * this.PageIndex; }
}

event EventHandler<PageEventArgs> IPageableItemContainer.TotalRowCountAvailable
{
add { base.Events.AddHandler(EventTotalRowCountAvailable, value); }
remove { base.Events.RemoveHandler(EventTotalRowCountAvailable, value); }
}

protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
int rows = base.CreateChildControls(dataSource, dataBinding);
// if the paging feature is enabled, determine
// the total number of rows in the datasource

if (this.AllowPaging)
{
// if we are databinding, use the number of rows that were created,
// otherwise cast the datasource to an Collection and use that as the count

int totalRowCount = dataBinding ? rows : ((ICollection)dataSource).Count;
// raise the row count available event

IPageableItemContainer pageableItemContainer = this as IPageableItemContainer;
this.OnTotalRowCountAvailable(new PageEventArgs(pageableItemContainer.StartRowIndex,pageableItemContainer.MaximumRows,totalRowCount));

// make sure the top and bottom pager rows are not visible
if (this.TopPagerRow != null)
{
this.TopPagerRow.Visible = false;
}

if (this.BottomPagerRow != null)
{
this.BottomPagerRow.Visible = false;
}
}

return rows;
}

protected virtual void OnTotalRowCountAvailable(PageEventArgs e)
{
EventHandler<PageEventArgs> handler = (EventHandler<PageEventArgs>)base.Events[EventTotalRowCountAvailable]; if (handler != null)
{
handler(this, e);
}
}
}

[/sourcecode]

With this extended version of a SPGridView, you should now be able to have all of that DataPager / templated goodness.

SPGridView Deep Dive: Custom Filter Menu Values

Over the last few days, I’ve learnt far more about SPGridView than I’d ever wanted to know, and here’s a gnarly case I worked out and thought I’d share the knowledge!

As a base, I’m hoping you’ve set up a fully functioning SPGridView with custom sort and paging – that’s covered via a combination of my previous blog posts on SPGridViews and maybe this guide to the ObjectDataSource itself. If you’re accessing any substantial sort of dataset, you’ll want to be using custom paging and custom sorting simply to avoid selecting massive datasets on every GridView operation. Lucky for us, SPGridView hooks into your ObjectDataSource much like a normal grid view so you shouldn’t have too much trouble here.

What I was looking at doing, was seeing how far I could customize the Filter dropdown – specifically, there was a requirement in the specification I was building to for the dropdown menu to have categories, which the SPGridView would filter off.

So it kind of looks like below:

If you’ve got the normal automatic SPGridView filtering going, you’ll know that it really just gives you a ginormous list of all the possible values for you to pick from, as your filtering options. That’s not really ideal for a few reasons though, since if you have a large number of potential values, this operation can get really expensive (hence why we wanted to use categories).

So, the steps that I ended up doing to achieve filter by category:

  1. hook into the postback for when the FilterMenuPreOpen is called
  2. work with a hidden BoundField column
  3. ensure the sort condition is still valid
  4. javascript override for the SPGridView_FilterCallbackHandler

Hook Into The Postback For When The FilterMenuPreOpen is called

So you’re probably wondering how SharePoint comes up with the filter values in the first place – it turns out that what it does behind the scenes when you open that dropdown menu is that it actually calls your ObjectDataSource’s select method again (with a page count of 0) and (possibly also DataBinding to something at some stage, then) returns the correct filter values. We made our performance totally awesome by *not* having our select method on our ODS grab all items that ever existed, so what the filter dropdown is requesting is not ideal.

We need a way to determine within the select method, whether it’s a normal select operation, or whether it’s a populate call for the filter drop down menu. And luckily, someone somewhere made it possible for us to do so – we can check for the presence of the “__CALLBACKPARAM” – if the filter dropdown has been called, Context.Request.Form["__CALLBACKPARAM"] will contain __SPGridView__;FilterColumn, where FilterColumn is the internal name of the column from your DataTable.

So, at the top of your select method for your ODS, you can do something like:

[sourcecode language="c-sharp"]
if (!String.IsNullOrEmpty(Context.Request.Form["__CALLBACKPARAM"]))
{
string[] callbackParam = Context.Request.Form["__CALLBACKPARAM"].Split(‘;’);
if (callbackParam.Length == 2)
{
switch (callbackParam[1])
{
case "MyFilterColumn":
dt.Rows.Add(0, … ,callbackParam[1], …, 0);
//add a row for every category you want to add to your filter menu if you are not doing a custom order
return dt;
}
}
}
[/sourcecode]

One thing to note is that we’re still returning a DataTable, and you must make sure the columns match the DataTable your SPGridView normally binds to or SharePoint will complain and throw an error in Javascript when you try to open that dropdown. The only value you need to populate in your DataTable rows are the ones for the correct column being filtered on (which explains the 0 values in the sample above). At this stage, if you’re not interested in controlling the order of the categories being rendered, you can just create a Row for each category you want and return your ‘filter set’ DataTable, but because I want to control the order I’m passing through the filter column name back. This will make more sense when we get to the Javascript override near the end.

Now that we’ve customized the contents of the Filter Menu, we need to make sure filtering still works: make sure your select method looks at the FilterExpression on your ObjectDataSource, and applies the correct “filter” to your SQL select statement, or other such data-grabbery.

However – there’s some voodoo black magic which I couldn’t work out where even though your ODS select method looks at the incoming filter expression, grabs data, and returns an appropriate DataTable, if the selected filter value doesn’t exactly match the incoming data, the row gets discarded. It’s easier to explain with an example; so say you change your Filter DataTable to return “0 – 10″, “11 – 20″ and “20 – 30″ – you’ll find that when you choose to filter on 11 – 20, the SPGridView will claim no rows were found (even though you stepped through your code and verified the DataTable being returned by the select statement has rows), because the filter column values were, say, 14, 12 and 19, but none were “11 – 20″ exactly (if anyone knows why SharePoint does this, please let me know…)

So to get around this, we work with a hidden BoundField column (thanks to super colleague Alla for the suggestion)

Since we know the filter does some magic checks against the actual value of the column after our select statement, we’re going to split our one column into two – one to control the Filtering, and one to control the actual data.

So take your SPGridView, and modify it:

[sourcecode language="c-sharp"]

column = new BoundField();
column.DataField = "MyFilterColumn";
column.SortExpression = "MyFilterColumn";
column.HeaderText = "My Filter Column";
appGridView.Columns.Add(column);

column = new BoundField();
column.DataField = "MyFilterColumnData";
column.SortExpression = "MyFilterColumnData";
column.HeaderText = "My Filter Column Data"; //won’t actually be seen anyway
column.Visible = false; //hidden data column – swap out the values @ render time.
appGridView.Columns.Add(column);

[/sourcecode]

And the basic idea is to fill the MyFilterColumn with the category (eg 1 – 10), and the MyFilterColumnData with the actual value (eg 5), but when the grid is being displayed, overwrite the category display for each DataRow with the actual column data (since displaying a whole bunch of 1 – 10 is not really that useful). To perform the data substitution, we can use the RowDataBound event on the SPGridView:

[sourcecode language="c-sharp"]
private void appGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
//do substitution
if (sender != null && e.Row.RowType == DataControlRowType.DataRow)
{
object dataItem = e.Row.DataItem;
e.Row.Cells[4].Text = (e.Row.DataItem as DataRowView)["MyFilterColumnData"].ToString();
}
}
[/sourcecode]

In the example above, the index for the Cells array is the 0-based index for your SPGridView’s Columns Collection – you’ll want to be targeting the cell that normally displays the value of “MyFilterColumn”.

After doing all this, our black magic filter-check is now happy (since the selected filter value technically matches in the background), but we see the correct results. Excellent!

At this stage, it’s a good idea to make sure your Sort Condition is still valid – it should be fine since if you’ve set up the hidden bound columns the way I’ve set out above, the column name hasn’t changed, but it’s worth confirming sorting still works as you expect it to.

The final piece of the puzzle is the javascript override for the SPGridView_FilterCallbackHandler. As mentioned previously, you don’t have to do this if you don’t care about what order your filter categories are presented in – SharePoint gives it to you in alphabetical order by default as far as I can tell, which is probably fine for most cases. However, it’s not okay when you’ve got a set of categories like:

  • 1 – 10
  • 20 – 50
  • 100 – 250

Since it goes by alphabetical order, when you open the filter dropdown, you’ll actually get 1 – 10, followed by 100 – 250, then 20 – 50; not quite what we’re after. We can fix this by understanding a little bit about the clientside stuff that goes on when you hit that Filter menu drop down, and a bit of reflector…

Looking in the CreateChildControls method for the SPGridView class:

[sourcecode language="c-sharp"]

[SharePointPermission(SecurityAction.Demand, ObjectModel=true)]
protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{

if (this.AllowFiltering && !string.IsNullOrEmpty(this.FilterDataFields))
{
//some stuff

for (int k = num1; k < Math.Min(this.Columns.Count, (int)strArrays.Length – num2); k++)
{
DataControlField dataControlField = this.Columns[k];
string str = strArrays[k + num2];
if (dataControlField != null && !string.IsNullOrEmpty(str))
{
//some stuff here

if (this.HeaderRow != null)
{
Menu menu = new Menu(dataControlField.HeaderText);

//stuff

string[] strArrays1 = new string[5];
strArrays1[0] = "SPGridView_FilterPreMenuOpen(‘"; // Look – a JS call
strArrays1[1] = SPHttpUtility.EcmaScriptStringLiteralEncode(this.ClientID);
strArrays1[2] = "’, ‘%TEMPLATECLIENTID%’, ‘%MENUCLIENTID%’, ‘";
strArrays1[3] = SPHttpUtility.EcmaScriptStringLiteralEncode(str);
strArrays1[4] = "’, event); ";
menu.ClientOnClickPreMenuOpen = string.Concat(strArrays1);

//other stuff

}
}
}
}

}

[/sourcecode]

You can see above it’s attaching a ClientOnClick event to the SPGridView that calls SPGridView_FilterPreMenuOpen; so the whole kind of cycle (in my mind) goes:

User clicks –> SPGridView_FilterPreMenuOpen (in JS) -> a javascript EvalCall –> internal callback that calls the ODS Select method –> SPGridView_FilterCallbackHandler (in JS)

So from JS it does a postback, grabs the values, and then the javascript callback handles some data related to the ODS select method call and creates all the dropdown menu items. You can see the full definitions of the SPGridView_FilterPreMenuOpen and SPGridView_FilterCallbackHandler methods in the 14 hive in the Layouts folder, inside the spgridview.debug.js file…but back to our problem.

When we generate our DataTable in the very first step (if the callbackargument was for the filter dropdown), SharePoint doesn’t respect the order in which the rows are added to that DataTable. Somewhere along the line, it gets ordered alphabetically, and this is what gets thrown back as the eval result into the SPGridView_FilterCallbackHandler. So to get around it, we can extend SPGridView_FilerCallbackHandler to ignore the result of the eval call, and specify our categories at the Javascript level.

Here’s an example of how to do so – I added this directly to my .ascx but you should probably have it in a separate .js file, or something:

[sourcecode language="javascript"]
<script type="text/javascript">
var SPGridViewFCHBase = SPGridView_FilterCallbackHandler; //store the original definition
SPGridView_FilterCallbackHandler = function (result, context) {
var filterList = result;
if(filterList === "MyFilterColumn")
{
filterList = "1 – 10;20 – 50;100 – 250";
}
SPGridViewFCHBase(filterList, context);
}
</script>
[/sourcecode]

So remember in the example above, where I just threw back the name of the filter column? Here we check if that’s what’s present, and if so, set the appropriate list of categories for the filter. It’s just a semi-colon delimited list, so you can pretty much have as many categories as you like, in an order you control.

And there you have it! Performant category based filtering for your SPGridView. Hopefully the *next* person who has to do this will have less trouble than I did.

Interesting fact: if you look into spgridview.debug.js, you’ll see that there’s a blank method called SPGridView_FilterMenuSort that’s never called – I suspect the SharePoint team at one stage were planning to allow you to hook into this to specify the order of your filter values, but this probably got canned somewhere along the line…

Gotcha: ListView Control Only Paging Once (a.k.a How Did We Get Work Done Before The Internet)

Here’s the scenario:

I had a ListView control in a Visual Web Part running in SharePoint 2010 with a script manager on the page – but my List View would only display correctly on page load, and after one paging command, then no longer.

With the power of Google Bing, I came across a very similar situation and resolution online.

It turns out that while I checked everything in the ASP.NET pipeline, I had just assumed that because I was inserting this webpart into an existing site I’d be all set up for jQuery, but turns out I was getting script errors due to the missing jQuery reference.

So the moral of the story is – if you’ve got an Ajaxified control that’s only paging once, check your page for script errors / javascript errors.

Yay for collective experience!

Strong Naming Assemblies For Sharepoint Part 2: Updating Specific Version References

Without access to the source code for assemblies, you can add sign / add strong names for them for use in SharePoint via ildasm and ilasm (for which the instructions I previously wrote about).

However, consider the scenario where:

Assembly A (unsigned) has a reference to a specific version of Assembly B (also unsigned).

I tried going the regular ilasm route, but Visual Studio kept complaining that it was expecting the unsigned version of Assembly A (version=1.0.0.0 publickeytoken=null). There were a few mentions of hooking up to the AssemblyLoad/Binding parts during run-time, but that still wouldn’t solve our compile-time errors.

Enter this blog post about changing and rebuilding assemblies to update referenced assemblies – turns out all we need to do to get our situation working properly is to insert the public key token as part of the reference.

Before the ilasm step, open up the .il file, and at the top you can see the referenced assemblies and edit yours to include the PKT:

[sourcecode]
// Metadata version: v2.0.50727
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.assembly extern My.Assembly
{
.publickeytoken = (B4 5D C7 B6 5B C4 C7 0E ) // .z\V.4..
.ver 1:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 3:5:0:0
}
.assembly extern System.Web
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_….:
.ver 2:0:0:0
}
[/sourcecode]

My guess, as stated on StackOverflow, was that with specific version referencing, the publickeytoken requirement is implicit which is why we needed to define it – but if anyone knows more or has a cleaner way of porting both unsigned assemblies to signed versions, let me know! :)

SPGridView Gotcha #2: Performance Issues / DataBinding multiple times

Going off my previous SPGridView post a few days ago, I ramped up the testing for the SPGridView to grab some data from a live service hosted online somewhere. However, the performance for the SPGridView was terrible – it took somewhere within the range of 5-6 seconds to switch between pages of 10 items.

Busting out the ULS logging and debugging tools, it turns out the Select method on the ObjectDataSource was being called multiple times (nine, to be exact) instead of only the once that was necessary. After a lot of head scratching and reflector, I worked out the answer.

It turns out that by following Erik Burger’s blogpost and code, by having the grid view columns set up on the Render method, by that time it was too late and the GridView was already bound to the ODS so every new column that was being added triggered a databind + select on the ODS… which if you multiply out by the number of columns in your table, makes it a pretty big performance hit.

Check out the StackOverflow question for more details (including why I don’t actually even need to call DataBind() myself at all, but the moral of the story is – not everything on the internet (which includes this post) is ever going to be 100% correct all the time :)

SPGridView Gotcha: Filtering, ObjectDataSource and You

Giving the SPGridView a good kick around today, seeing if it’ll fit the bill for our development work – I came across two really great resources which I highly recommend for anyone looking to get a SPGridView up and going:

- Erik Burger’s blogposts, Part 1 and Part 2
- Kit Menke’s note on potential filtering bugs with data that contains apostrophes

So following those posts, I got my SPGridView up and going and everything seemed to be in working order, *except* the Filtering which even after following the apostrophe notes kept returning the “Missing operand after ‘x’ operator” error message.

After some trial and error, it turns out that the column name needs to be one single word. I was filtering on a column named Time Elapsed in the back end, ie:

[sourcecode language="c-sharp"]
column = new BoundField();
column.DataField = "Time Elapsed";
column.SortExpression = "Time Elapsed";
column.HeaderText = "Time Elapsed";
appGridView.Columns.Add(column);
[/sourcecode]

When I renamed the DataField and Sort Expression to “TimeElapsed” instead (leaving the header text as two words), all my errors disappeared and everything went great! I don’t know if they never tested the “Total Sales” filtering in the examples linked to on Erik’s blog, but this fixed it for me so it’s one more thing to try for anyone who’s getting errors while filtering.

Signing Compiled Assemblies To Meet Sharepoint’s Strong Name Requirements

Recently been working on some SharePoint stuff which required using a few external libraries – and as you may well know, SharePoint requires you to have strong named assemblies (ie, signed) for them to be deployed to the GAC. So what happens if you’re given a compiled .dll, but not the source?

Turns out that with a bit of command line / dev tool magic, you can decompile and recompile (with key) any given assembly, which will make SharePoint less likely to cry. The steps are outlined here, but you’ll essentially want to do the following from a VS.NET command prompt:

  • Generate a KeyFile: sn -k keyPair.snk
  • Obtain the MSIL for the provided assembly: ildasm providedAssembly.dll /out:providedAssembly.il
  • Rename/move the original assembly: ren providedAssembly.dll providedAssembly.dll.orig
  • Create a new assembly from the MSIL output and your assembly KeyFile: ilasm providedAssembly.il /dll /key= keyPair.snk

The only gotcha for SharePoint 2010 (not sure about the upcoming 2013) is that if you’ve got .NET 4.0 installed, the path defaults to using the .NET 4.0 ilasm, which will generate a .NET 4.0 assembly (which you can’t use with SharePoint). To fix this, simply update the PATH variable in the command prompt to exclude C:\Windows\Microsoft.NET\Framework\v4.0.30319 and include C:\Windows\Microsoft.NET\Framework\v2.0.50727 instead.

If you’re signing assemblies that have specific version references, take a look at part 2 which shows you how to update those to include the new publickeytokens.