CAML Query to include all folders

I was working on a CAML query that retrieves all pages in a Publishing Web pages library, based on the content type. However, later on in the project, all these pages were moved into their corrosponding sub-folders. Instantly, my previously working CAML query stopped working as excepted.

The catch was, in order for a CAML query to include folders and subfolders when executing, you have to set the ‘ViewAttributes’ property to “Scope=’RecursiveAll'”. Otherwise only the root folder will be searched.

The entire CAML Query would look something like this:

The complete caml query, including the scope.

The complete caml query, including the scope.

Gotcha!

Export modified default Workflow to .wsp

Today I wanted to use a SharePoint 2010 based workflow in SharePoint 2013. I choose for a default workflow, and modified the workflow in a few different areas, such as the default emails that were being sent out. That Approval Workflow is great, except for the dodgy emails you get right?

Since I work in a team, it was important that the rest of my team members were also able to install the same workflow, without having to edit it themselves. So I needed a way of exporting the workflow to Visual Studio. What surprised me was that the ‘Save as template’ option was greyed out. 

Workflow_1As the documentation at http://msdn.microsoft.com/en-us/library/jj819316.aspx describes, you can only save a SharePoint 2010 based workflow as a template if this is a Reusable Workflow. However, the default workflows provided with a SharePoint 2013 Publishing site are all globally reusable workflows. Thus, the export button is greyed out.

Resolving this issue is actually very straight forward. If you click on the ‘Copy and Modify’ button:

Workflow_2

You will be prompted for a few different options. For the ‘Choose a base contenttype’ option, make sure you select ‘All’, otherwise chances are you will not get the option to use this workflow for creating major versions of a page (in case you are modifying the approval workflow). Give the workflow a name and description and click OK. The newly created workflow will be a reusable workflow, and not a globally reusable workflow. This means the ‘Save as template’ option is no longer greyed out, and you can continue on exporting the workflow as .wsp which you can then import into Visual Studio for all your team members to enjoy. Gotcha!Workflow_3

Web Template and Multi-server farm

Today I came across a weird issue when trying to provision a custom web template through Central Administration. I had created the onet file and things worked fine in my development environment. However when switching to the test environment, selecting my template from the Central Administration ‘Create Site Collection’ page and hitting ‘Create Site’ resulted in errors: Feature with ID {guid} is not installed in this farm.

That’s weird, right? I am sure I have deployed my solutions to the Web Application that the site collection was to be created at. Turns out, if you have a multi-server farm and your Application Server is not hosting the Web Applications – deploying a solution to a specific Web Application does not install the features for the Application Server thus – it cannot find them.

The solution is simple: When creating the site collection from the Central Administration, pick the ‘Select a template later’ option. After the site has been created – browse to it and select your custom template. Since you are now on the site, the code will be executed by the Web Frontend Server which can find your installed solutions no problem. Gotcha!

URL Redirect based on a list in SharePoint 2010 and 2013

Consider the following scenario:
You have an existing website on a platform other than SharePoint, which you are going to migrate. There are thousands of existing links on other websites that you want to remain functional, however in the new SharePoint based website, these pages are stored in different places. You want a central place where users can manage the old links, and tell the users where they have to be redirected to. You would also like to implement ‘Friendly URLs ‘ where the user can type in
http://www.somelink.com/friendlyURL and be redirected to http://www.somelink.com/en-EN/subsiteX/subsiteXX/notsofriendlyURL.aspx . These friendly URLs also have to be managed by the website administrator, without having to touch the underlying infrastructure (and specifically IIS).

The solution:
To implement this functionality you can combine a few different SharePoint features with some clever ASP.NET mechanics. Specifically you will need these components:

  • A SharePoint List which contains a field for the ‘Old URL’ and a field that specified the ‘New URL’;
  • A HttpModule that handles page requests
  • A SharePoint Feature to deploy the list, as well as a feature to add the HttpModule to the web.config settings

So let’s get to it and see how we can implement this functionality! (A link to the demo solution is included at the bottom)

Note: This solution assumes that the base URL of the old and new website remains the same. If you are trying to redirect from http://www.websitea.com to http://www.websiteb.com , you will need an additional redirect in IIS that handles the base redirect to websiteb. For this solution to work, the request has to actually be handled by SharePoint.

Note 2: This solution and the demo project is based on SharePoint 2013, although the principle will work for SharePoint 2010 as well.

Step 1
Let’s start by creating our SharePoint Solution. Create an empty SharePoint 2013 project, and add two features to it: one Site scoped feature which we will use to deploy our list, and one Web Application scoped feature which we will use to deploy our web.config modifications.

Step 2
To deploy our list we can choose between the ever-lasting discussion: XML v.s. Code . Personally I am a big fan of creating Lists through code. Right click the Lists feature and click ‘Add Event Receiver’. Uncomment the ‘FeatureActivated’ code and include the following code snippit to create the list: CreateList
The above code will create a list named ‘URLRedirect’ which contains three fields:

  • OldUrl: text field used for storing the old URL which we want to redirect
  • NewUrl: Text field used for storing the new URL that we want users to be redirected to
  • IsPermanent: Boolean field which is used in our solution to determine if we want to use a 301 redirect (in case of site migration, a 301 redirect is more search engine friendly and overall a better way to redirect), or a normal redirect (in case of a Friendly URL)

Step 3:
In our project, we create business entity classes that represent the list items. Doing this allows you to separate your business logic from the WebParts / Modules which makes it easier to re-use this functionality. Right click the project and add a new Class, I’ve named mine URLRedirectBE. You can find the entire class in the downloadable project, but the important bit here is:Screenshot 2
If you just want to get the example working, you could also simply create a method that retrieves the ‘NewUrl’ value based on the ‘OldUrl’ value, which is what the method above does for you.  

Step 4:
Now that we have the List and the connection to the List set up, we need to create our HttpModule which actually handles the users’ requests and redirects them if they hit a page that does not exist. To do this, simply add another class to the project and let it inherit from IHttpModule. For this to function you need to include a reference to ‘System.Web’ in your project. The class you would need is included in the demo project, but the important bit is shown below:
Screenshot 3In the above code we check for a 404 error code, which is the error if a page cannot be found. Another requirement for us was to only perform this check for three types of files: .html, .htm and .aspx. That is why there is an extra check in there. Checking for a 404 error code means that the URL Redirect will only work if the request is not made to a valid page to begin with. If you do want to always check for the list, all you have to do is omit the error code check. This also means that we can only check the URL Redirect list after most of the request has already been server. Although it is a bit slower, this is the earliest point in which we can make the distinction between a 404 and an existing page.

Step 5:
The final step is to create the web.config modification that registers our custom http module in the SharePoint web.config. To do this, right click the Web Application feature and click ‘Add event receiver’. Include the code below to the FeatureActivated method:Screenshot 4
And for the sake of completeness, include the following code in the FeatureDeactivating method:Screenshot 5Simply deploy everything, activate the features and enjoy!

You can download the entire demo solution here.

If you have any comments, please do not hesitate to leave a reply and I will try to get back to you ASAP.

Sources used for writing this blog post are included below:
Waldek Mastykarz –
http://blog.mastykarz.nl/sharepoint-2007-redirect-solved-using-301-instead-of-302-redirects/

Gustavo Velez – http://www.developer.com/net/asp/article.php/10917_3812301_2/Extend-the-Flexibility-and-Functionality-of-SharePoint-with-HTTP-Modules-and-Handlers.htm