Karine Bosch’s Blog

On SharePoint

SharePoint Saturday

SPS 2012 Belgium

SharePoint Saturday 2014 is coming near and we all start to feel the vibes. April 26th is the big day! We just made the session agenda available online. Check it out here!

April 8, 2014 Posted by | SharePoint 2010 | Leave a comment

New release of CAML Designer available!

042813_0652_Newversiono1.png

My friend Andy Van Steenbergen and I worked very hard to prepare a new release of the CAML Designer. We didn’t aim at adding new functionality; we rather preferred to solve a number of bugs. You can download the new version on the BIWUG site under the Download tab.

We also have the impression that the server object model works much slower than the client object model. Therefore we switched the default work mode to client object model.

There are also a number of bugs that were reported but that are not included in this release:

  • The <Membership> element is missing
  • For complex queries, the CAML query can be included in the REST call
  • Taxonomy fields: only top-level of multi-select field was visible

The reason why these bugs are not solved yet, is because these bugs are not that simple to solve and we didn’t want to wait much longer with this release because of the fixes that are already in it. We will try to solve the remaining bugs as soon as possible.

We hope you enjoy the improvements. If you would encounter bugs or have a good idea on how we could further improve the CAML Designer, please don’t hesitate to report it to camlfeedback@biwug.be  or leave a note on this blog. Together we can make it a better tool.

Show hidden fields

In some cases you want to build a filter based on a value in a hidden field. By default the CAML Designer doesn’t show hidden fields. To solve this issue we added the check box “Show hidden fields” to the user interface just above the list treeview. By default the hidden fields are not displayed, but you can click this check box to get them displayed.

Show hidden fields

Long Display Names

One of our users als reported that there were issues with long display names. It would ask a lot of redesign to have this properly displayed so we chose to add a tooltip that shows the complete display name. We hope that this suits your needs.

Long display names

Boolean fields

There was also a problem with querying boolean fields. This issue is now solved:

  <Where>
      <Eq>
         <FieldRef Name='VeryTall' />
         <Value Type='Boolean'>1</Value>
      </Eq>
   </Where>

I tested and retested, and this query returns rows:

Boolean field query result

User and UserMulti fields

There were a number of problems when filtering on a User field or UserMulti field. These have been solved. Now, you can choose between filtering on the current user or on a specific user.

User field - current user

If you choose to filter on the current user, your query will look as follows:

   <Where>
      <Eq>
         <FieldRef Name='AssignedTo' />
         <Value Type='Integer'>
            <UserID />
         </Value>
      </Eq>
   </Where>

If you choose to filter on a specific user then you can enter or the name of the user or its ID. If you enter the name of a user, your query looks as follows.

   <Where>
      <Eq>
         <FieldRef Name='AssignedTo' />
         <Value Type='User'>Karine Bosch</Value>
      </Eq>
   </Where>

If, at the other side, you want to filter on the user ID, the following query is generated, indicating that you are passing an ID:

   <Where>
      <Eq>
         <FieldRef Name='AssignedTo' LookupId='True' />
         <Value Type='Integer'>4</Value>
      </Eq>
   </Where>

The FileRef field

There was also a problem when trying to filter on FileRef. When you now select the FileRef field on the Where tab, you get a lookup displaying all folders in the selected document library.

FileRef field

When you select a folder, the query is built as follows:

   <Where>
      <Eq>
         <FieldRef Name='FileRef' />
         <Value Type='Lookup'>/Shared Documents/Folder 2</Value>
      </Eq>
   </Where>

REST snippet for lookup fields

Based on a blog post of Andrew Connell “Applying Filters to Lookup Fields with the SharePoint 2013 REST API“, we also updated how the REST snippet for lookup fields is generated:

$.ajax({
   url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Cities')/Items?$expand=Country/Title&$filter=Country/Title eq 'France'",
   type: "GET",
   headers: {"accept": "application/json;odata=verbose"},  
   success: onDataReturned; 
   error: onError; 
   function onDataReturned(data){ // TODO: handle the data }; 
   function onError(err) { // TODO: handle the error }
});

Taxonomy Fields

We also added functionality to retrieve list data based on the ID of a taxonomy field. The difficulty here is that a term has a name and an guid in the term store. You can retrieve list data based on a term name but this is dangereous as term names can change over time.

Taxonomy Field

   <Where>
      <Eq>
         <FieldRef Name='Technology' />
         <Value Type='TaxonomyFieldType'>SharePoint</Value>
      </Eq>
   </Where>

When a term is used to tag a list item, this term is stored in a hidden list on site collection level. At this time, the term gets an ID, which is stored internally as WssId.

This release of the CAML Designer now offers the possibility to query on this ID:

Taxonomy Field by ID

The query instantly changes as follows:

   <Where>
      <Eq>
         <FieldRef Name='Technology' LookupId='True' />
         <Value Type='Integer'>1</Value>
      </Eq>
   </Where>

It will retrieve the same list items as when you would have queried on the term “SharePoint”.

The Test tab

The Test tab displays now a label that indicates the number of rows that are returned by the result set. Once the number becomes visible, you know that the retrieval has finished. This is handy when your query does not return a result and no grid becomes visible. The number zero will indicate that the query is finished but that no results have been returned.

March 17, 2014 Posted by | CAML Designer, SharePoint 2013 | 1 Comment

SharePoint Saturday Belgium

SPS 2012 Belgium

On Saturday April 26th we are having our 4th SharePoint Saturday. When it was officially announced to our members, it only took 48 hours to be sold out. Today we officially communicate the sessions that are elected. As always we try to have a right mix of sessions for developers, IT Pro and business people. We also target a variety of domains of SharePoint 2013, like Apps, Search, Workflows and BI. As in the previous years, we also have a good mix of foreign speakers and local speakers. Some of them are coming back for the 3th time.

If you’re curious, browse right away to the speakers page on the SPS site to get a detailed overview of all sessions! I hope you will be as excited as we are!

Hope to see you there!

 

March 12, 2014 Posted by | BIWUG | Leave a comment

SharePoint 2013 SP1 is available for download now!

The release of SP1 for SharePoint 2013 has been announced on February 25th. It is available for download from the Microsoft Download Center.

My colleague Tom Van Gaever did a nice job in listing all issues that have been solved in SP1.

You can find the official documentation here.

 

March 5, 2014 Posted by | SharePoint 2013 | Leave a comment

SharePoint Saturday 2014 is coming soon!

SPS 2012 Belgium

The BIWUG board is proud to announce a new edition of SharePoint Saturday Belgium!

The event takes place on Saturday – of course :) – April 26th at the same location as the previous years: Xylos, St-Lendriksborre 8, 1120 Brussels.

The call for speakers will open today and of course the subscriptions too! Keep an eye on twitter and the BIWUG site if you want to be amongst the first to subscribe.

January 20, 2014 Posted by | BIWUG | Leave a comment

Declaring a taxonomy field that allows multiple values

There are two different types of taxonomy fields:

  • TaxonomyFieldType: This defines a taxonomy field to store a term to tag the list item.
  • TaxonomyFieldTypeMulti: This defines a taxonomy field that allows users to tag the list item with more than one term from the same term set.

When using CAML, you can declare taxonomy fields as follows:

  <Field  ID="{CB736B25-C980-4688-B076-1C5315B20092}" 
          Name="ProductCategory" DisplayName="Product Category" 
          Type="TaxonomyFieldType"
          ShowField="Term1033" 
          EnforceUniqueValues="FALSE" 
          Group="XYZ Site Columns" 
          SourceID="http://www.xyz.be/v1" />

  <Field  ID="{6E8C115D-43DE-4AD9-9DE4-27F5D4C008F4}" 
          Name="ProductCategories" DisplayName="Product Categories" 
          Type="TaxonomyFieldTypeMulti"
          ShowField="Term1033" 
          EnforceUniqueValues="FALSE" 
          Group="XYZ Site Columns" 
          SourceID="http://www.xyz.be/v1" />

This will create your field of the correct type but it will not be mapped to a term set yet. This cannot be done through CAML, but only through code, ideally in the feature receiver:

   field.SspId = termStore.Id;
   field.TermSetId = termSet.Id;
   field.AnchorId = Guid.Empty;

These properties mean:

  • TermSetId: This is the Guid of the term set to which the field is mapped. Users will only be able to tag the item with term(s) from this term set.
  • AnchorId: If the entry point for tagging is a term within the term set, the anchor id needs to be set to the guid of this term. If the entry point for tagging is any term within the term set, this property does not need to be set.
  • SspId: This is the Guid of the term store to which the term set belongs.

You would think that, when you create a field of type TaxonomyFieldTypeMulti, you would be able to store more than one term, but unfortunately that’s not the case.

When you inspect the field in the user interface, you see that the check box Allow multiple values is not checked.

It’s only after having checked this property that you are able to store more than one term using the TaxonomyFieldValueCollection. Unfortunately there is no attribute in CAML to set this checkbox, so you will have to solve this in your feature receiver by setting the AllowMultipleValues property:

if (field.TypeAsString == "TaxonomyFieldTypeMulti")

      field.AllowMultipleValues = true;

As of then you will be able to store multiple terms in the taxonomy field.

December 20, 2013 Posted by | SharePoint 2010, SharePoint 2013 | 2 Comments

Programmatically provisioning a TaxonomyField of type TaxonomyFieldTypeMulti

I had a hard time finding out how I could save multiple terms to a field of TaxonomyFieldTypeMulti using the SharePoint server object model.

The following code worked out for me:

        private static void SetTaxonomyValue(SPListItem item, Term term, string fieldName)

        {

            if (term != null && item != null && item.Fields[fieldName] != null)

            {

                if (item.Fields[fieldName].TypeAsString == "TaxonomyFieldType")

                {

                    TaxonomyField taxonomyField = item.Fields[fieldName] as TaxonomyField;

                    TaxonomyFieldValue taxvalue = new TaxonomyFieldValue(taxonomyField);

                    taxvalue.TermGuid = term.Id.ToString();

                    taxvalue.Label = term.Name;

                    item[fieldName] = taxvalue;

                }

                else if (item.Fields[fieldName].TypeAsString == "TaxonomyFieldTypeMulti")

                {

                    TaxonomyField taxonomyField = item.Fields[fieldName] as TaxonomyField;

                    TaxonomyFieldValueCollection taxvalues = 

item[fieldName] as TaxonomyFieldValueCollection;

                    if (taxvalues == null)

                        taxvalues = new TaxonomyFieldValueCollection(taxonomyField);

                    TaxonomyFieldValue taxvalue = new TaxonomyFieldValue(taxonomyField);

                    taxvalue.TermGuid = term.Id.ToString();

                    taxvalue.Label = term.Name;

                    taxvalues.Add(taxvalue);

                    item[fieldName] = taxvalues;

                }

            }

        }

 

When the taxonomy field is of type TaxonomyFieldTypeMulti, terms are stored as a TaxonomyFieldValueCollection. The trick is that you first have to test whether you already have a term available in the collection or not. If not, you have to initialize the collection, otherwise you will get a “null reference” exception when you try to add a term to the collection.

December 19, 2013 Posted by | SharePoint 2010, SharePoint 2013 | Leave a comment

Programmatically provisioning a term set for navigation

I’ve been experimenting with Managed Metadata and one of the things that I’ve been doing is automating the provisioning a navigation term set using the SharePoint server object model.

In your code you will have to add a reference to the Microsoft.SharePoint.Taxonomy.dll.

First you have to find the correct instance of the term store:

   TaxonomySession session = new TaxonomySession(site, true);

   TermStore termStore = session.TermStores[mmsName];

Then you have to find the correct group to which you want to add your term set. In SharePoint 2010 you could only create groups from within the Central Administration and the term sets in these groups could be accessed by any site collection with the correct permissions.

   termGroup = termStore.Groups[groupName];

But in SharePoint 2013 you can also have a group on site collection level. To retrieve this group you have to use a new method:

   termGroup = termStore.GetSiteCollectionGroup(site);

If you want the term set to be used for navigation, you have to add your term set to the local group:

   TermSet termSet = termGroup.CreateTermSet(termsetName);

And you also have to configure that this term set is going to be used for navigation:

   NavigationTermSet navigationTermSet = NavigationTermSet.GetAsResolvedByWeb(termset, site.RootWeb,

                    StandardNavigationProviderNames.CurrentNavigationTaxonomyProvider);

   navigationTermSet.IsNavigationTermSet = true;

Good to know that the NavigationTermSet class is defined in the Microsoft.SharePoint.Publishing.Navigation namespace of the Microsoft.SharePoint.Publishing.dll.

And then you can start creating the hierarchy of terms that is needed for your site navigation:

   Term term = termSet.CreateTerm(termName, 1033);

In the meantime you can also set the friendly URL.

   NavigationTerm navigationTerm = navigationTermset.Terms.Where(

nt => nt.Id == term.Id).FirstOrDefault();

   navigationTerm.FriendlyUrlSegment.Value = termUrl;

You could also set other properties like the Navigation Hover Text, the Simple Link Url or the Target Url. You could also define whether the term should be excluded for global navigation.

But I had a hard time finding how to change the Navigation Node Title programmatically. It seems that there is no property foreseen for this. I tried to set the Title property of the NavigationTerm but this is a read-only property and reflects the name of the term itself.

When working in the user interface, you can also see that you change the Navigation Node Title, which is set to the name of the term by default:

In Reflector I found that NavigationTerm derives from NavigationTermSetItem and that it has a method named SetCustomizableStringCustomValue(Enum, string) which is not publically accessible. The protected enum is defined as follows:

There you can see that there is indeed a property Title that could map the Navigation Node Title.

I found 2 methods on the Term class that I thought I could use: SetCustomProperty(string, string) and SetLocalCustomProperty(string, string). But both methods created a custom property (which is then visible on the Custom Properties tab).

My friend Tom Van Gaever, who works as a PFE at Microsoft Belgium, pointed out to me that you can set custom properties using the SetLocalCustomProperties method and that properties like the Navigation Node Title have a special name:

  • _Sys_Nav_Title: the Navigation Node Title
  • _Sys_Nav_FriendlyUrlSegment: the Friendly Url, also represented by the FriendlyUrlSegment property of the NavigationTerm class.
  • _Sys_Nav_TargetUrl: the target URL, also represented by the TargetUrl property of the NavigationTerm class.
  • _Sys_Nav_TargetUrlForChildTerms: the target URL for child terms, also represented by the TargetUrlForChildTerms property of the NavigationTerm class.
  • _Sys_Nav_CatalogTargetUrl: the catalog target URL, also represented by the CatalogTargetUrl property of the NavigationTerm class.
  • _Sys_Nav_CatalogTargetUrlForChildTerms: the catalog target URL for child terms, also represented by the CatalogTargetUrlForChildTerms property of the NavigationTerm class.

And that was the key to my solution. By executing the SetLocalCustomProperty method on the _Sys_Nav_Title property, I was able to set the Navigation Node Title:

   term.SetLocalCustomProperty("_Sys_Nav_Title", "core business");

If you use that same method with a property name that does not exist, it will create a custom property (which is then visible on the Custom Properties tab); just like the SetCustomProperty method does.

Save your changes to the term store when you’re finished:

   termStore.CommitAll();

December 13, 2013 Posted by | SharePoint 2013 | 7 Comments

CAML Designer 2013 – Summer Update

042813_0652_Newversiono1.png

While I was on holiday my friend Andy van Steenbergen released a new version of the CAML Designer. He solved a number of bugs and also added snippets for PowerShell!

You can find more details about the new release in Andy’s blog post and download the new version from the biwug site on the download tab.

If you find bugs, you can always report them to camlfeedback@biwug.be.

Nice work Andy! :)

August 28, 2013 Posted by | CAML Designer | 2 Comments

In search for the Index Component

At the company I work for, we are going to start working with synonyms in our Search results (we are still on SharePoint 2010). The synonyms will be maintained by our Content Editors team and therefore I decided to let them maintain the synonyms in the term store (Managed metadata service application), as it is done in SharePoint 2013. Every night a timer job will run to read the term store and to create the tsenu.xml file and to copy it to the \Microsoft Office Servers\14.0\Data\Office Server\ApplicationsGUID-query-0\config\tsenu.xml folder.

When our code goes in production, it goes through a DTAP process, meaning that our code needs to be deployed on dev, on test, on acceptance before it goes in production. So we have different SharePoint farms for the different environments. Although the SharePoint folders our always deployed to the same drive, the folder for the tsenu.xml can be different as one of the folders is the GUID of the Search Service Aplication. So I wanted that the timer job would figure out the correct folder using the Search topology.

My colleague Manoj Malireddy figured out how to do this:

   SearchService s = new SearchService("OSearch14", SPFarm.Local);
   if (s != null)
   {
       var srchApp = from SearchServiceApplication sapp in s.SearchApplications
                     where sapp.Name == "Enterprise Search Service Application"
                     select sapp;

       SearchServiceApplication serviceApp = srchApp.FirstOrDefault();
       if (serviceApp != null)
       {
           var queryComponent = serviceApp.QueryTopologies.ActiveTopology.QueryComponents.FirstOrDefault();
           if (queryComponent != null)
           {
               string serverName = queryComponent.ServerName;
               string directoryPath = queryComponent.IndexLocation;
               string foldername = queryComponent.Name;

               string configfoldername = directoryPath + "\\" + foldername + "\\Config";
           }
       }
   }

August 1, 2013 Posted by | Search, SharePoint 2010 | Leave a comment

Follow

Get every new post delivered to your Inbox.

Join 155 other followers