Karine Bosch’s Blog

On SharePoint

Add or Modify SharePoint 2013 Search Topology using a PowerShell built User Interface

In SharePoint 2013, there is no real user interface to modify the search topology. Well, there is, but you can only use for a single server farm. If you have more servers in your SharePoint farm, you have to do this through PowerShell.

One of my South-African Premier Field Engineer colleagues Scott Stewart developed a tool on top of PowerShell WITH UI to create or modify a search topology.

Read more about it here: “Add or Modify SharePoint 2013 Search Topology using a PowerShell built User Interface

A few screenshots to get you curious :)

Search topology tool

Search topology

It looks like a very promising tool! Have fun with it!

May 22, 2015 Posted by | Search, SharePoint 2013 | Leave a comment

Creating fields using CSOM in SharePoint 2013

Recently, I was working on a project where we wanted to create SharePoint fields using the .NET client object model (CSOM). You can easily find examples on the internet on how to create a text field, but we had a lot of trouble to find out how to create a calculated field.

Calculated fields can be created in a number of flavors. The following code snippet generates a calculated field that will show employee data as follows:

Karine Bosch (id 82176)

string formula = "<Formula>=FirstName&amp; \" \" &amp;LastName&amp; \" (id: \" &amp;EmployeeID&amp; \" \"</Formula>"
      + "<FieldRefs>"
      + "<FieldRef Name='FirstName' />"
      + "<FieldRef Name='LastName' />"
      + "<FieldRef Name='EmployeeID' />"
      + "</FieldRefs>";

string schemaCalculatedField = "<Field ID='<GUID>' Type='Calculated' Name='FullName' StaticName='FullName' 
   DisplayName='Full Name' ResultType='Text' Required='TRUE' ReadOnly='TRUE'>" + formula + "</Field>";
Field fullNameField = demoList.Fields.AddFieldAsXml(schemaCalculatedField, true, AddFieldOptions.AddInternalNameHint);
clientContext.ExecuteQuery();

You can read more on how to create other type of fields using CSOM here.

Tip

To learn how to provision a calculated field, I created this type of field in a blank site through the UI of SharePoint. Then I saved the site as template. This saves the site as a .wsp and stores it in the Solution gallery. From there you can download it and import it in Visual Studio.

Import wsp

Once the .wsp imported, you will notice that all fields, content types, list instances and other elements that make up your site are translated into CAML and features:

Import wsp 2

Click on the elements.xml in the Fields folder to see the definition of all fields.

 

May 14, 2015 Posted by | CSOM, SharePoint 2013 | Leave a comment

Setting the value of a lookup field using CSOM

Today I had a hard time to find out how to set the value of a lookup field using CSOM. In most of the code samples I found on the internet, the LookupId is set hard coded, and this is not what I needed. Additionally, in some cases the lookup list was situated on the root web, and in another case I had to query a different field than the Title field. I ended up writing the following method:

public static FieldLookupValue GetLookupValue(ClientContext clientContext, string value, 
   string lookupListName, string lookupFieldName, string lookupFieldType, bool onRootWeb)
{
     List list = null;
     FieldLookupValue lookupValue = null;

     if (onRootWeb)
     {
          list = clientContext.Site.RootWeb.Lists.GetByTitle(listName);
     }
     else
     {
          list = clientContext.Web.Lists.GetByTitle(listName);
     }

     if (list != null)
     {
         CamlQuery camlQueryForItem = new CamlQuery();
         camlQueryForItem.ViewXml = string.Format(@"<View>
                  <Query>
                      <Where>
                         <Eq>
                             <FieldRef Name='{0}'/>
                             <Value Type='{1}'>{2}</Value>
                         </Eq>
                       </Where>
                   </Query>
            </View>", lookupFieldName, lookupFieldType, value);

          listItemCollection listItems = list.GetItems(camlQueryForItem);
          clientContext.Load(listItems, items => items.Include
                                            (listItem => listItem["ID"],
                                             listItem => listItem[lookupFieldName]));
          clientContext.ExecuteQuery();

          if (listItems != null)
          {
              ListItem item = listItems[0];
              lookupValue = new FieldLookupValue();
              lookupValue.LookupId = Int.Parse(item["ID"].ToString());
          }             
     }

     return lookupValue;
}

This method works on both SharePoint 2010 and 2013.

I hope this code snippet can help others.

Enjoy!

 

May 11, 2015 Posted by | CSOM, SharePoint 2010 | Leave a comment

New release of CAML Designer available with new functionality!

042813_0652_Newversiono1.png

This weekend we released a new version of the CAML Designer.We solved the bug that occurred when more than one TaxonomyField was selected in the Where clause; but we also include the following new functionality:

– The <Membership> element

– REST snippets including a CAML query

We are very proud with these new additions, and we hope you like it!

 

 The <Membership> element

The <Membership> element already exists for ages but it’s only now that we introduce it in the CAML Designer.

Whenever you select a field of user type in the Where clause, you will now get an additional radio button “Membership”:

User field

When you click the Membership option, you get an additional dropdown where you can select one of the following options:

  • CurrentUserGroups: this will retrieve all tasks that are assigned to groups to which the current user belongs.
  • SPWeb.Groups: this will retrieve all tasks that are assigned to groups.
  • SPWeb.AllUsers: this will retrieve all tasks that have been assigned to users and not to groups.
  • SPWeb.Users: this will retrieve all tasks that have been assigned to users that don’t belong to a specific group but that have been granted access to the site directly.
  • SPGroup: this will retrieve tasks that have been assigned to a specific group.

User field - membership

We’ve also foreseen a small description field that explains the selected option:

User field - membership CurrentUserGroups

When selecting the SPGroup option, another additional dropdown becomes available. This dropdown will list all groups:

User field - membership SPGroup

Selecting a group from this dropdown will retrieve all tasks that have been assigned to the selected group. The CAML query looks like the following:

   <Where>
      <Membership Type='SPGroup' ID='5'>
         <FieldRef Name='AssignedTo' />
      </Membership>
   </Where>

When you select the CurrentUserGroups option, the CAML query will look as follows:

  <Where>
      <Membership Type='CurrentUserGroups'>
         <FieldRef Name='AssignedTo' />
      </Membership>
   </Where>

For the SPWeb.Groups option, the CAML query looks like this:

  <Where>
      <Membership Type='SPWeb.Groups'>
         <FieldRef Name='AssignedTo' />
      </Membership>
   </Where>

For the SPWeb.AllUsers options, the following CAML query is generated:

  <Where>
      <Membership Type='SPWeb.AllUsers'>
         <FieldRef Name='AssignedTo' />
      </Membership>
   </Where>

And when you select the SPWeb.Users option, you will get the following CAML:

  <Where>
      <Membership Type='SPWeb.Users'>
         <FieldRef Name='AssignedTo' />
      </Membership>
   </Where>

Credits go to Christoper Clementen with his blog post: http://christopherclementen.wordpress.com/2012/08/27/caml-query-membership-attribute where he clearly explains how the <Membership> element works.

 

REST snippets executing CAML queries

A second new functionality are the REST snippets with CAML queries. In most cases you can use the well known REST requests using the select and filter criteria to retrieve list items. But there are a few cases where such a REST request will return an error. These cases are:

  • filtering on taxonomy fields
  • the <Membership> element

In these cases your REST snippet must include a CAML query. Additionally this REST request needs to be executed as a POST. This is well described in this blog post of CleverWorkarounds.

Such a REST snippet generated by the CAML Designer looks like this:

 

$.ajax({ 
   url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Developers')/GetItems(query=@v1)?"
        + "@v1={\"ViewXml\":\"<View><ViewFields><FieldRef Name='Title' /><FieldRef Name='FirstName' /><FieldRef Name='Company' /></ViewFields>"
        + "<Query><Where><Eq><FieldRef Name='Technology' /><Value Type='TaxonomyFieldType'>SharePoint</Value></Eq></Where></Query></View>\"}", 
   type: "POST", 
   headers: { 
         "X-RequestDigest": $("#__REQUESTDIGEST").val(), 
         "Accept": "application/json;odata=verbose", 
         "Content-Type": "application/json; odata=verbose" 
   }, 
   success: function (data) { 
      if (data.d.results) { 
         // TODO: handle the data  
         alert('handle the data'); 
      } 
   }, 
   error: function (xhr) { 
      alert(xhr.status + ': ' + xhr.statusText); 
   } 
});

When filtering on membership, the REST snippet will look like this:

$.ajax({ 
   url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Tasks')/GetItems(query=@v1)?@v1={\"ViewXml\":\"<View><Query><Where><And><Neq><FieldRef Name='Status' /><Value Type='Choice'>Completed</Value></Neq><Membership Type='SPWeb.Groups'><FieldRef Name='AssignedTo' /></Membership></And></Where></Query></View>\"}", 
   type: "POST", 
   headers: { 
         "X-RequestDigest": $("#__REQUESTDIGEST").val(), 
         "Accept": "application/json;odata=verbose", 
         "Content-Type": "application/json; odata=verbose" 
   }, 
   success: function (data) { 
      if (data.d.results) { 
         // TODO: handle the data  
         alert('handle the data'); 
      } 
   }, 
   error: function (xhr) { 
      alert(xhr.status + ': ' + xhr.statusText); 
   } 
}); 

May 22, 2014 Posted by | CAML Designer, SharePoint 2013 | 2 Comments

Where are the SharePoint assemblies?

In SharePoint 2013, the SharePoint assemblies are located in the \Windows\Microsoft.NET\assembly\GAC_MSIL\ directory:

SharePoint 2013 assemblies

All other SharePoint files are located in what we call the 15 hive: \Program Files\Common Files\Microsoft Shared\Web Server Extensions\15.

When inspecting IIS, you will notice a change in the virtual directories: the _layouts folder still points to the 14 hive (containing the SharePoint 2010 files), while there is an additional sub folder that points to the 15 hive (containing the SharePoint 2013 files).

SharePoint virtual folders

 

When navigating through the file system, you can see that there is still a 14 hive, containing folders like TEMPLATE, TEMPLATE\CONTROLTEMPLATES and TEMPLATE\LAYOUTS. When you edit one of the controls in the CONTROLTEMPLATES folder, you will notice that they still reference the old SharePoint v14 assemblies. If you deploy your SharePoint 2010 solutions and features to your SharePoint 2013 farm, it is in this 14 hive that you will find your files.

But there is no ISAPI folder anymore in the 14 hive, nor are the assemblies in the Global Assembly Cache. Calls to the old assemblies are redirected to the SharePoint v15 assemblies. This redirection is defined in special policy files located in the \Windows\Microsoft.NET\assembly\GAC_MSIL\ directory:

SharePoint policy files

 

April 19, 2014 Posted by | SharePoint 2013 | Leave a comment

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 | 3 Comments

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

Follow

Get every new post delivered to your Inbox.

Join 185 other followers