Wednesday, 30 November 2011

Search Refiners and the Search Box

​Something that isn't normally the case is to remove the Search Box from the out-of-the-box search results page. More often than not, it's a requirement to have it present so the user can see the query they're currently searching with. However, recently, a client insisted on removing this from their search results page.

Now, I've already given the game away here in the title of this article: some of the search refiners functionality stopped working. Which bit? Well, nothing overly important - simply the "show more" option that appears in the refiners when more than a specified number of refiners are present. More to the point is why it happens?

Having examined pages with and without the Search Box, it appears the Search Box Web Part is responsible for adding a JavaScript function and a reference to the search.js file. The function is effectively a check for the search.js, but without it the "show more" option will fail as it calls this function first and as it can't find it, it doesn't work.

The following was an extract I added to my Search Results Xslt to get the page to function correctly:

function SearchEnsureSOD() {
    EnsureScript('search.js', typeof(RenderTaggingControl));
}
_spBodyOnLoadFunctionNames.push('SearchEnsureSOD');

The "typeof" used by the EnsureScript function call is usually against GoSearch but this is present only when the Search Box Web Part is present. I've used RenderTaggingControl instead as this is present when the refiners are present.

Monday, 28 November 2011

CSS and JavaScript Bundling and Minification

Unfortunately, this is not something ​immediately available, but it looks like this will be in the next version of Visual Studio. The bundling features I've read about will automatically bundle a specified selection of files into a single HTTP request.

The astute among you will probably already be aware that there's already support for JavaScript "bundling" in the current version of Visual Studio (and SharePoint) in the form of the Script Manager control which you can use to create what's called a Composite Script and something we've exploited in our SharePoint 2010 publishing projects. As the name implies, it only manages scripts so what it lacks is any kind of support for CSS.

The next version appears to not only enhance the current "bundling" functionality but also extend it for use with CSS files (and there may even be some possibility of extending this to other file types if the class model will allow). This means that multiple CSS files can then be "bundled" in the same way, thereby minimising the number of HTTP requests. Not only can we do that, but we will also be able to minify the bundled files.

Misspelled WordMinification is the process of removing unnecessary characters from a file, like spaces, carriage-returns, possibly semi-colons, comments etc. It can be used to reduce files size considerably, and if the file size is small, the HTTP request will be quicker to return to the browser. There are already sites out there that can be used to do this, but to have it within Visual Studio will be very useful. How much this will be integrated with SharePoint I don't know. As SharePoint is based on a specific version of the Misspelled Word.Net framework this functionality may not make it into the next version - we'll have to wait and see.

The main drive behind these changes appear to come from the necessity to provide a better web UX for mobile devices where low and slow bandwidth can inhibit use of a website. We'll just have to wait and see how and if it surfaces in the next version of SharePoint.

If you want to know more, check out Scott Guthrie's blog post: http://weblogs.asp.net/scottgu/archive/2011/11/27/new-bundling-and-minification-support-asp-net-4-5-series.aspx

Monday, 21 November 2011

Output a String With Escape Characters

Not something that is often required, but something that popped up today - how to get the literal output from a String object in C# including the escape characters.

So let's take a String variable declared like this:

string str = @"c:\temp";

The literal string is c:\temp, but what if we wanted the underlying escaped string which would look something like this:

"c:\\temp"

Not so easy.  Fortunately, Google being the fount of all knowledge these days, I put it to work in finding some help and unearthed a neat example from Stack Overflow using an Extension Method:

internal static class ExtensionFunctions
{
    internal static String ToLiteral(this String input)
    {
        var writer = new StringWriter();
        CSharpCodeProvider provider = new CSharpCodeProvider();
        provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
        return writer.ToString();
    }
}

To use it simply type str.ToLiteral(); and it will return the string complete with the escape sequence intact.

Friday, 18 November 2011

Using Parameter Binding

Nothing new here​, but Parameter Bindings (see Microsoft's article on them here) have been around for a while and more widely publicised for use with the Data Form and Data View Web Parts. Something not so widely know is that any web part inheriting from the Data Form Web Part also has the same functionality available.

This means useful web parts like Search Results, People Search Results, Content by Query Web Parts, Xslt List View Web Part, RSS Aggregator web part and more all have this available to them.

In SharePoint 2010, apparent new functionality made things like the query string available to the underlying Xslt in a Content by Query Web Part. The truth is that this was available in 2007 by using Parameter Binding and the QueryString Location property (as I blogged previously).

What is more useful, is that the Search Results and People Search Results now include a Parameter Binding property available through the web part toolpane which means that level of configuration can be done through the UI rather than hacking away at the underlying web part file. Entering the Parameter Binding is easy enough using the syntax:

<ParameterBinding Name="[name]" Location="[selected location]" />

for each property you want to use. The [name] is added into the Xslt for the Web Part as an Xsl Param and it's then available.

Useful, simply and quick. Something to bear in mind.

Thursday, 3 November 2011

Sandbox Solutions and the Update Panel

There are already several articles on the web​ relating to the use of the ASP.NET UpdatePanel in sandbox solutions, so to add to the mix, here's another one.

Sandbox solutions and the UpdatePanel: the truth of it is that you cannot use the UpdatePanel in sandbox solutions. If you try to use it you get an error stating "The control with ID 'UpdatePanel1' requests a ScriptManager on the page". Using the ScriptManager.GetCurrent returns null. If you try to add your own you get an error as you can only have one ScriptManager instance at a time. You can add your own, however, by adding it as the first control in the Form.Controls control tree, but even this will most likely break the page unless you duplicate the exact scripts you may be adding to the page in code - the symptom of this is the ScriptResource.axd that would normally contains your scripts returns with a 404.

That aside, the reason the ScriptManager.GetCurrent doesn't return the actual ScriptManager you have added to your page or master page is to do with the way sandbox solutions replace some objects with its own object types. For instance, the System.Web.UI.Page object is replaced by the SPUserCodePage object.

The question for me is why is the ScriptManager not available? Why not allow the use of the UpdatePanel in a sandbox?

Wednesday, 26 October 2011

Problems Adding Rest Service Reference in Visual Studio

If you ever have to add a Service Reference for the SharePoint List WCF Service to a project in Visual Studio 2010​ you may encounter a "Bad Request" or "There was an error downloading ..." type message even though you can view the results of the same service through a browser.

The way around this is very simple and resolves the problem, however, in my mind, this should only really be done on development machines to get around this issue and not rolled out across a Live installation. What you need to do is go to IIS and change the authentication methods for the _VTI_BIN folder to disable Anonymous access. That's it. You can then successfully add the service reference.

Tuesday, 18 October 2011

Custom Workflow Actions in SharePoint 2010

On a recent SharePoint 2010 project I had the opportunity to look at creating custom Workflow​ Actions which is a way to extend the actions already available in SharePoint Designer Workflows.
If I'm honest, the foray was both informative and slightly arduous but perhaps due mostly to my own inability to type properly and my own lack of understanding. Let's start by having a look at why we decided to look down this path.

Why a Custom Workflow Action?

The project in question required a handful of workflows to be developed, all of which were prepared and written using SharePoint Designer. The problem was highlighted early on that we needed to port the be able to package the workflows up to deliver them across multiple platforms during the development life-cycle.

For 2 of the workflows, this didn't pose a problem since they were Reusable Workflows which lend themselves to just this kind of functionality. The 2 workflow, however, was a List-based workflow and as such it was not able to be exported as a WSP. The reason the workflow was a List-based workflow was due to the columns necessary to facilitate the workflow actions - Approval Status being the culprit in this scenario. As it turns out, the "Approval Status" column is not visible for anything other than a List-based workflow.

To allow the workflow to be packaged up meant it had to be a Reusable Workflow, or we had to provide a work-around. After several attempts to package the workflow up (using this method http://ikarstein.wordpress.com/2011/02/10/walkthrough-how-to-move-or-copy-a-sharepoint-designer-2010-list-workflow-to-another-list-on-the-same-site-or-another-site/ was a way to export a List-based workflow using the "Export to Visio" and "Import from Visio" options which did work but didn't provide the hands-off approach we wanted) we decided to try writing a custom Workflow Action to perform the steps we required.

Nuts and Bolts

As it turns out, creating a custom Workflow Action is pretty straight-forward. Create a class, create a publicly declared static method in the class, and away you go. The first parameter must be a context object - we were deploying as a User Code Solution so this was of type SPUserCodeWorkflowContext.

If you're action doesn't need any parameters, do your coding stuff and then move on to the feature XML.

One note here - any typos or spelling mistakes mean that your workflow will not run. I battled for a long time to debug my workflow with only frustration as my reward. I eventually searched the SharePoint logs and found that I had mis-named a parameter so my workflow was never being run. Once I had fixed that, I was away after I had attached to the SharePoint User Code process.
Here's a couple of walk-throughs I found: http://msdn.microsoft.com/en-us/library/gg615449.aspx and http://msdn.microsoft.com/en-us/library/ff798499.aspx. What I would say is that the first article is more accurate. The second one makes no mention of the fact that the method you implement for your action should be a static method - even the example code doesn't show this, so beware.

End-to-end, the final solution (which wasn't overly complicated) took about a day, and at the end I had a fully working custom workflow action which I could use in my workflows. Looking back, it was actually quite painless and easy and once you know where to look (i.e. SharePoint logs, debugging etc) it was fairly rapid.

The Fairytale Ending(?)

Unfortunately, there is no happy ending to this story. I went through a day of trauma and frustration and came out the other side having happily implemented my custom workflow action into a reusable workflow. I saved the workflow through SharePoint Designer to a WSP and thought things were making sense.

I then moved the workflow to another site collection and installed the WSP and that's where the story currently ends. It didn't work. Well.....I say that it didn't work, but I don't really know if I'm honest. The only definition I have to say it didn't work is the fact that the workflow I had created did not appear anywhere so I was unable to use it. No doubt I will post further about this once I've figured out what went wrong here.

Final Thoughts

Looking back at the reasons behind our decision to use a workflow it was mostly dictated by the approach to the required functionality we had already started: namely the other 2 reusable workflows. Keeping to the same model for the third workflow made sense as it followed the same technology instead of departing in a different direction and introducing custom code instead of manully created workflow (i.e. event receivers).

As it turned out, writing a custom workflow action still meant code in order to achieve the portability we wanted so at that point, perhaps, it would have been better to write an event receiver. The influence to stick with workflow came from the technology angle - keeping to the same "hymn sheet" as it were. Yes, it was custom code, but at least it was still workflow.

Fortunately, in this scenario we did have a fallback position to backup the site and restore it, so the time invested was as much for research into this area, which, if I'm honest, was time well spent.