Skip to content

How to renew a SPFX certificate (gulp certificate)

Ok so this happened today for me.

Apparently on this computer I started working on spfx project more than 5 years ago and the certificate has expired.

 

 

 

I could not find how to renew it on the internet so here is how to do it:

 

gulp untrust-dev-cert

gulp trust-dev-cert

Bass/treble cut component

Ok, this is a first post in my Guitar Wiring series.

In this we will explore the bass/treble cut component.

Normal tone control on a guitar cuts the treble. In some cases, especially when dealing with a bassy and boomy neck pickup, you might want to cut a little bit of bass.

Using push/pull or push-push pot you can achieve this.

So, here we use a standard control pot, it could be 250K or 300K or 500K , but I highly recommend using the logarithmic ones. They are marked as A, so it could be A250K or A500K.

I mostly use humbucker guitars so A500K is what I use most of the time.

In the schematic below, this is the pulled-up position.

And this is the pushed down (default) position.

Now what is important to understand, the treble cut is usually connected to the path of the signal in parallel, like this:

The bass cut , or the bass/treble cut we are building, has to be in series, like this:

In general, it can go before or after volume control, in my case I am doing it before volume control, otherwise there will be the 50s wiring,

 

 

Anyways, here is the diagram:

 

 

C1 is the bass cut capacitor, you can use any value usually depending on how much cut you want, usual range is about 680pf to 2 nf, the larger the value, the less cut you will have.

C2 is your normal treble cut capacitor, I usually use 22nf for bridge or 15nf for neck, but common range is about 15nf to 47nf.

R1 is an optional resistor.

If you don’t use it, then when switching to bass, there will be no treble cut whatsoever. (the usual treble cut control has some small amount of cut even in the fully open position). To retain the “minimum open” treble, cut, we can put the 500K resistor in here. (assuming the 500K pot). You can put a trimpot and experiment with the values.

Changing SharePoint farm passwords

Another recent case from the customer. What they had is a farm which was deployed with autospinstaller. https://autospinstaller.codeplex.com/ So they have quite a number of accounts for various SharePoint services , windows services and application pools.   So how should we change the accounts? The easiest way (that was implemented at the customer) is to have account to be registered as managed accounts. This way you or SharePoint can automatically change passwords for the accounts, and update all relevant records. The managed account can change the passwords in AD or just update the SharePoint records. In our case there were some errors we have not resolved, so we have let the AD admins change the password and then we have changed the things in SharePoint.   So what happens after you change the AD account password? If you do nothing, there will be problems. Most likely though you will only notice the problems after you restart the server.   The reason is that there are Windows Service registrations on farm computers containing copies of the passwords IIS Pools registrations containing copies of the passwords In some cases (like search or workflow) other entities contain the reference to the password. Managed accounts The benefit of managed account is that SharePoint can automate some of these actions across the farm. Namely – changing the windows service registrations and iis pools registrations. If you choose to change the passwords (and not let them be changed automatically), there are basically 2 ways to do it. Option one – Central Admin   Press the edit button Enter new password and press ok below   Note that option one – Set account password to a new value will try to change the password in AD first. Option two will just update the relevant services and IIS pools. In some cases you would prefer to use PowerShell. If the account you are changing is also used to run the Central Administration application pool, then your command will kinda fail in the middle cause it will run under the pool that is going to be reset! In this case you can use the Set-SPManagedAccount command https://technet.microsoft.com/en-us/library/ff607617(v=office.16).aspx If you want this command to change the AD password use this format Set-SPManagedAccount -Identity $username -NewPassword $newpassword -ConfirmPassword $newpassword If you want to use an existing password – use this one. Set-SPManagedAccount -Identity $username -ExistingPassword $newpassword  -UseExistingPassword:$true I have made a script that reads accounts and new passwords from the csv files and updates them in a bulk. <# .SYNOPSIS Changes managed account passwords at the farm. .DESCRIPTION Changes accounts using the provided CSV file. .EXAMPLE .\changepasswords.ps1    -inputFile “yourfile.csv” -newPasswords:$false .NOTES Author: Marat Bakirov Date: 05 July 2016 #> [cmdletbinding()] param( [string] $InputFile = “accountsandpasswords.csv”, [switch] $newPasswords = $true ) #################################################### # Configurables #################################################### Add-PSSnapin Microsoft.Sharepoint.Powershell #################################################### # Main #################################################### function Main { $passwords = Import-Csv $InputFile $passwords | foreach { $username = $_.Username $newpwd1 = $_.NewPassword $newpassword =  ConvertTo-SecureString -String $newpwd1 -AsPlainText -Force $newpwd1 if ($newpasswords) { Write-Host “changing password for  {$username} to a new one” Set-SPManagedAccount -Identity $username -NewPassword $newpassword -ConfirmPassword $newpassword -Confirm:$false } else { Write-Host “changing password for  {$username} to an existing one” Set-SPManagedAccount -Identity $username -ExistingPassword $newpassword -Confirm:$false -UseExistingPassword:$true } } } Main How to change other passwords If the account participates in the user profile sync, search or workflow farm, you  might need to run additional scripts. User profile sync These accounts are managed and are changed within SharePoint but are also used for the User Profile Sync. So an additional configuration might be required. Good reference can be found here https://blog.zubairalexander.com/managing-passwords-for-service-accounts-in-sharepoint-sql-server/ – section 5 5. User Profile Synchronization Connection Account or https://blogs.msdn.microsoft.com/charliechirapuntu/2013/01/16/sharepoint-2010-service-accounts-passwords-change-guide/   Search crawler account This has an additional impact – the search content account has to be updated in the active directory first and then updated in the search center. https://technet.microsoft.com/en-au/library/dn178512.aspx   Workflow and service bus farm accounts     On each server in the farm that has workflow installed run the Service Bus PowerShell in the elevated mode. (Note: if the service buspower shell is missing, then skip the procedure for this server). Run the changewfpassword.ps1 script. The script will prompt for the new Password for the svcInsiteWfProd/ svcInsiteWfTest  account.   Write-Host “Please enter a new password” $passwordText = Read-Host $AccountPassword = ConvertTo-SecureString -String $passwordText -AsPlainText -Force Stop-WFHost -Verbose Update-WFHost -RunAsPassword $AccountPassword –Verbose Start-WFHost -Verbose Stop-SBHost -Verbose Update-SBHost -RunAsPassword $AccountPassword –Verbose Start-SBHost -Verbose   Source code The scripts could be found here   https://1drv.ms/f/s!AguWtH15ywzQhI5kUYLXI1Jcmv4Y6Q  

Case – broken export-spweb. (Understanding the solution package version and DeploymentServerType)

Another case from the recent customer support work. The customer had a 3rd party solution with a list template, list and a web part which seemed to be created for SharePoint 14 (2010) originally and simply recompiled. (And I cannot change or recompile the sources).   The customer has SharePoint 2013 farm, made of 2 App servers (let us call them APP1 and APP2) and 2 web front ends (WEB1 and WEB2). APP1 also runs central admin.   Another 3rd party backup solutions the customer is using is doing a granular SharePoint backup (up to document) and internally uses the Export-SPWEB command.   The Export command breaks. Errors are similar to the ones described here: https://social.technet.microsoft.com/Forums/en-US/6b50d0f2-b323-4156-a11a-d3f6ea1492c7/sharepoint-2010-site-collection-export?forum=sharepointgeneralprevious   Error: Feature ‘d57f4817-f1f9-42aa-863c-139804c731b0’ for list template ‘100’ is not installed in this farm.  The operation could not be completed.   During investigation I have found out the few reasons.   First – the 3rd party solution was installing in the 14 Hive. What?   The solution files and features were added to the “C:\Program Files\Common Files\microsoft shared\Web Server Extensions\14\TEMPLATE\FEATURES\”  but NOT added to the “C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\FEATURES\”   Apparently the solution was compiled with the 14 compatibility option.     Probably it is not a good idea to go through all servers and copy the files, so to achieve the result we need to tell SharePoint to deploy the solution to both 14 and 15 hives. Would be simpler if the solution would recompiled with 15 compatibility option, but I could not do it, so I had to run the following command to deploy the solution   Install-SPSolution -Identity <yoursolution.wsp> -AllWebApplications -GacDeployment -CompatibilityLevel {14,15}
  This made the files to appear at the 15 hive. However, the files were only deployed to the WEB1 and WEB2, and the export command were still not working at the APP1 and APP2, despite the fact that it started to work fine at the WEB1 and WEB2.   The customer was really reluctant to run the Export jobs at the Web frontend and thus increasing the load.   To understand why the files did not appear at the APP1 and APP2, let us look at another setting:   So this setting is telling us if the solution will be deployed to web front end or an application server. But how does SharePoint define which server is the application server?   Well you might assume that it is server role. https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spserverrole.aspx
  For SP2013 it seems that this does not matter. It seems that the  Sharepoint defines the web front end as a server that runs a “Microsoft Sharepoint Foundation Web Application” service.   If the solution package deployment type is “WebFrontEnd”  – it’s assets are deployed  to the servers that have the “Microsoft Sharepoint Foundation Web Application” on. So the solution was simple – start the Microsoft Sharepoint Foundation Web Application service on the server? Simple?   One more tricky thing. Starting the service on the server that has a Central Admin – causes the IIS to restart, and thus central admin to restart. So we may encounter the problem. In this case run the command     Get-SPServiceInstance | where {$_.TypeName.Contains(‘Web Application’)} | ft -Property Id,TypeName,Server,Status -Autosize   Find the service instance on the server you want it to run on, and then run the Start-SPServiceInstance -Identity <guid> command     That is all! the case is solved. So we have fixed the version by installing the solution with the correct compatibility levels and also added a Web Role to the application servers.   Woah woah woah wait a second. What? Added a Web Role to the application servers??? Yes, however we did not break the farm topology. These servers APP1 and APP2 HAD the “Microsoft Sharepoint Foundation Web Application” service but were NOT used as Web  Front ends. Simply the load balancer had no idea they do have the IIS and so the requests were not redirected here. We just solved the problem.        

How to display correct document links in the search results.

At the recent client project there were an interesting situation. They had a web part that was looking pretty much like a list with the only difference – it was a Content Search webpart and it was supposed to show certain the documents from all subsites. Pretty usual request.

However, the client pointed out, that the links are not the same as if they would use the “normal” documents view. The client was not happy that the links suggest to download the file instead of opening in Word/Excel/etc.

I have started to look.

There were a number of reasons why the links were different.
First reason is that they use  Path  managed property.
Path managed property gives what it gives. The path.
Like this

http://sp131:82/Documents/excel1.xlsx

But it does not respect existence of the Excel services or the OWA.
So I found this blog post

http://www.eliostruyf.com/three-useful-managed-properties-for-working-with-office-web-apps/

That was probably the only one explaining other important managed properties

  • ServerRedirectedURL
  • ServerRedirectedPreviewURL
  • ServerRedirectedEmbedURL

 

So I have used the ServerRedirectedURL. At the customer environment it returns a link to OWA, like this:


http://server/_layouts/WopiFrame.aspx?sourcedoc={E526E4B1-6759-448F-B6C6-0C67E942173B}&file=Documents/excel1.xlsx&action=default&DefaultItemOpen=1

 

At my local SharePoint dev single server machine it looked like this


http://sp131:82/_layouts/15/xlviewer.aspx?id=/Documents/excel1.xlsx&DefaultItemOpen=1

 

Another difference was the way the links work. In the library itself the links tried to open the corresponding app – word or excel or the OWA. In the search results there were no prompt for opening the App.

 

There is a setting that affects this behaviour It is well described in this article

https://technet.microsoft.com/en-us/library/ee837425.aspx

2016-07-18_16-27-06

 

You can find it under “advanced” settings in the document library, and there are some other system wide settings that affect it.

 

I have looked at the links in the list and found out that the links look like this

 

When the library setting is like “open in the client application”.


<a class="ms-listlink ms-draggable" href="/Documents/doc1.docx" onmousedown="return VerifyHref(this,event,'0','SharePoint.OpenDocuments','')" onclick="return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','','','1','1','0','0x7fffffffffffffff')" dragid="1" draggable="true">doc1</a>

When the library setting is like “open in the browser”.


<a class="ms-listlink ms-draggable" href="/Documents/doc1.docx" onmousedown="return VerifyHref(this,event,'1','SharePoint.OpenDocuments','')" onclick="return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','1','SharePoint.OpenDocuments','','','','1','1','0','0x7fffffffffffffff')" dragid="1" draggable="true">doc1</a>

In my case the customer was ok with hardcoding the option one. So the final resulting code was like this



<!--#_
var linkURL = $getItemValue(ctx, "Path");
linkURL.overrideValueRenderer($urlHtmlEncode);
var ServerRedirectedURLValue = '';
var ServerRedirectedURL = $getItemValue(ctx, "ServerRedirectedURL");
ServerRedirectedURL.overrideValueRenderer($urlHtmlEncode);
ServerRedirectedURLValue = ServerRedirectedURL.defaultValueRenderer(ServerRedirectedURL);
if ( (ServerRedirectedURLValue == null) || (ServerRedirectedURLValue == undefined) || (ServerRedirectedURLValue == ''))
ServerRedirectedURLValue = linkURL.defaultValueRenderer(linkURL);
var onmousedown = "return VerifyHref(this,event,'0','SharePoint.OpenDocuments','1" +ServerRedirectedURLValue +"')";
var onclick = "return DispEx(this,event,'TRUE','FALSE','FALSE','SharePoint.OpenDocuments.3','0','SharePoint.OpenDocuments','','1"+ServerRedirectedURLValue+"','','2','0','0','0x7fffffffffffffff')";
_#-->
<a class="cbs-Line1Link ms-noWrap ms-displayBlock"
onmousedown="_#= onmousedown =#_"
onclick="_#= onclick =#_"
href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= line1LinkId =#_">_#= line1 =#_</a>

 

How to add “View Library” link to the SharePoint Search results from file share

Recently a customer asked me to improve one little thing.
You know the “view library” link that appears once you search for the files in SharePoint?

These guys had setup a search over a file share, but the library link did not appear there.
Apparently the solution appeared to be rather simple. However, I did not find anything in the internet and the customer did not as well.
I assume you are familiar with the display templates concept in the SharePoint 2013. There templates are used to display search results and actually they are JavaScript files (or, in the case of SharePoint Standard, HTML files that generate the JS files).

So the links are rendered by the Item_CommonHoverPanel_Actions.html
This part renders the “View Library” link.


if(!Srch.U.e(ctx.CurrentItem.ParentLink) && ctx.CurrentItem.csr_ShowViewLibrary) {
_#-->

<!–#_
}

While debugging I have found out that the CurrentItem.ParentLink is not filled.
I could not find out why it happens that way for the file shares, however, once I found this, the fix became very simple. I have added this simple piece of code before the block.

//ignia custom code
var url = ctx.CurrentItem.csr_Path;
if (url.indexOf('file://') >=0)
{
var lastIndexOfSlash = url.lastIndexOf('/');
if (lastIndexOfSlash > 0)
{
ctx.CurrentItem.ParentLink = url.substring(0,lastIndexOfSlash);
}
}

Simple!

How to deal with “Missing server side dependencies” error

In this post I am going to show my methodology for dealing with the “Missing server side dependencies” error. I do not have a good way to deal with it online but one good way to deal with it on-premises.

For this example I am using the SharePoint 2010, but the problem is the same in the newest versions (though honestly I did not check it on the SharePoint 2016).

This error appears in the SharePoint Health Analyzer

and looks like this:

Let us think for a second – why does this error happen and what is the inner reason for it?

Let us say your server side solution has some artefact. In this case it is the web part. Once upon a time the web part was a part of the solution and was deployed somewhere. Then you have decided you do not need the web part or simply has renamed it. However the content database already contains an information like “page xxx has a web part yyy in this zone with this settings”.

And if the webpart does not exist the database is inconsistent.

It is not necessary a web part. You can add a ghosted module file and then decided to rename it. So the SharePoint will keep the information about the file in the database but the file will not be there.

Could be also that the web part gallery (_catalogs/wp contains information about your webpart and the webpart is also part of farm solution and do not exist anymore)

So the first step is to find where the web part is.

The way I was always doing it is via SQL. With the SQL you can search through the content database and find that specific string.

I have been making and losing the script the number of times, most recent time I have found a script in here

http://stackoverflow.com/questions/591853/search-for-a-string-in-all-tables-rows-and-columns-of-a-db

And I have slightly modified it so it not only shows the table where the string is stored, but also specific lines.

use WSS_Content — could be your database name here

DECLARE
@search_string VARCHAR(100),
@table_name SYSNAME,
@table_schema SYSNAME,
@column_name SYSNAME,
@sql_string VARCHAR(2000)

SET @search_string = ‘yourwebpart’

DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ‘BASE TABLE’

OPEN tables_cur

FETCH NEXT FROM tables_cur INTO @table_schema, @table_name

WHILE (@@FETCH_STATUS = 0)

BEGIN
DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @table_schema AND TABLE_NAME = @table_name AND COLLATION_NAME IS NOT NULL — Only strings have this and they always have it

OPEN columns_cur

FETCH NEXT FROM columns_cur INTO @column_name
WHILE (@@FETCH_STATUS = 0)
BEGIN

— SET @sql_string = ‘IF EXISTS (SELECT * FROM ‘ + QUOTENAME(@table_schema) + ‘.’ + QUOTENAME(@table_name) + ‘ WHERE ‘ + QUOTENAME(@column_name) + ‘ LIKE ”%’ + @search_string + ‘%”) PRINT ”’ + QUOTENAME(@table_schema) + ‘.’ + QUOTENAME(@table_name) + ‘, ‘ + QUOTENAME(@column_name) + “”

SET @sql_string = ‘IF EXISTS (SELECT * FROM ‘ + QUOTENAME(@table_schema) + ‘.’ + QUOTENAME(@table_name) + ‘ WHERE ‘ + QUOTENAME(@column_name) + ‘ LIKE ”%’ + @search_string + ‘%”) SELECT * FROM ‘ + QUOTENAME(@table_schema) + ‘.’ + QUOTENAME(@table_name) + ‘ WHERE ‘ + QUOTENAME(@column_name) + ‘ LIKE ”%’ + @search_string + ‘%”’

EXECUTE(@sql_string)

FETCH NEXT FROM columns_cur INTO @column_name

END

CLOSE columns_cur

DEALLOCATE columns_cur

FETCH NEXT FROM tables_cur INTO @table_schema, @table_name

END

CLOSE tables_cur

DEALLOCATE tables_cur

Once I have run the script I have seen this:

So now I know that the site with ID 089D94D0-7BF4-4A51-9E29-2BACABC30DF4 contains a missing web part in the gallery, I guess I could just delete it? A simple get-spsite PowerShell command could find me the site and the gallery.

Here is another example of another webpart. This time we can see it happens on 2 different web sites – a default site and a personal site of the administrator.

However, running this script is not enough. This is another good script that will find your webpart on all pages.

SELECT Webs.FullUrl, Webs.Title, AllDocs.DirName, AllDocs.LeafName, AllWebParts.tp_DisplayName, AllWebParts.tp_ID

FROM AllDocs, Sites, AllWebParts, Webs

WHERE Webs.Id = Sites.RootWebId AND AllDocs.Id = AllWebParts.tp_PageUrlID

AND Sites.Id = AllDocs.SiteId AND tp_WebPartTypeId IN (

SELECT DISTINCT tp_WebPartTypeId FROM AllWebParts (NOLOCK)

WHERE tp_WebPartTypeId IS NOT NULL AND tp_Assembly IS NULL AND tp_Class IS NULL)

— if you add this line, the script will find your specific web part instead of giving you all web parts on all pages

— AND (AllWebParts.tp_DisplayName = ‘yourwebpartname’)

Results of the script when run with my webpart:

Pic4.

Now depending on the number of pages and problems you could either clean the pages manually or make a script that will go through the pages and delete the webpart from it.

One more hint to finish this. Recently I met a problem I could not solve easily. Some users had added the obsolete Web Part to the Personal View of the page. So the script that would clean the web part could not delete this or even find the users! The content database did not help in this case.

So the simplest way to remove all personalized settings and the faulty/missing webpart from the page is to add the ?contents=1 to the page URL. This will bring the page into maintenance mode.

Here is how you remove all personal users settings

And here is how you delete the problematic web part from the page

Sharepoint dev machine – keep your SQL databases sizes neat

Ok, time to go back to the blog posting.

 

I do often create single-server SharePoint based environments purely for development purposes. In this environment we often face an issue of overgrowing databases logs.

To make things worse, now I use SSDs in Azure, which are rather limited in size.

So for DEVELOPER machine it would be fine to switch the recovery model to simple and thus the log should be truncated.

Prior to SQL 2012, there was a special option “truncate log on checkpoint”, but as of SQL 2012 I cannot find this option anymore. See https://technet.microsoft.com/en-us/library/ms187310(v=sql.105).aspx

 

The blog here http://microtechpoint.com/index.php?route=blog/article&article_id=10 contains a good set of commands to keep your database in place (I really like the title “Shrinking Ginormous SharePoint Database Transaction Log Files” :)), but it only deals with one database.

 

So I have found an undocumented procedure sp_MSForEachDB (you could read more here http://www.c-sharpcorner.com/UploadFile/63f5c2/sp_msforeachtable-stored-procedure-in-sql-server-2012/ or here http://weblogs.sqlteam.com/joew/archive/2008/08/27/60700.aspx ) that can run a particular command on every database.

 

The final syntax I use comes like this (but, of course, you could use your commands and avoid shrinking or set autoshrink if it suits your environment).

EXEC sp_MSforeachdb ‘USE [?]; print ”?”;  ALTER DATABASE [?] SET RECOVERY SIMPLE; CHECKPOINT; DBCC SHRINKDATABASE ([?],10); ‘

 

Disclaimer: I am not in any case saying that simple recovery model is ok for production.

Hope this post would be useful.

 

SharePoint : Clicking the icon in Type column is highlighting the item instead of launching the document

Our customer has complained that in the old SharePoint they used to have, they could click on the document Icon, and this would open the document. In a new SharePoint, click makes a selection click in the list.

So the customer really wanted us to make this icons clickable.

I have found a number of solutions, and they all were not satisfactory for me.

Official Microsoft answer:

https://support.microsoft.com/en-us/kb/2457975

suggests to change the default xsl file on the server. WE have Office 365.

One of the most interesting solutions was here

https://spdociconlink.codeplex.com

(

you do not have to install the whole solution, as the core you can find in this file

https://spdociconlink.codeplex.com/SourceControl/latest#SPDocIconLink/SPDocIconLink/ControlTemplates/SPDocIconLink/SPDocIconLink.ascx

which just does a CSR override for the DocIcon field.

)

The disadvantages of this solution:

  1. Checkin/Checkout status is not shown. Usually there is a little override icon.
  2. When you have an OWA, the clicks on the documents does not open the editor, instead, the file is getting downloaded.

So I came with the solution that reuses the built-in functions, and so has all advantages of the proper icon and the opening of the OWA files.

function CustomIcon(ctx, field, listItem, listSchema) {
if (ctx.CurrentItem.FSObjType == ‘1’) { /* a folder*/
var ret = [];
ret.push(ComputedFieldWorker.DocIcon(ctx, field, listItem, listSchema));
}
else {
var ret = [];
ret.push(“<a href=\”” + ctx.CurrentItem.FileRef);
ret.push(“\” onmousedown=\”return VerifyHref(this,event,'”);
ret.push(listSchema.DefaultItemOpen);
ret.push(“‘,'”);
ret.push(listItem[“HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon”]);
ret.push(“‘,'”);
ret.push(listItem[“serverurl.progid”]);
ret.push(“‘)\” “);
ret.push(“>”);
ret.push(ComputedFieldWorker.DocIcon(ctx, field, listItem, listSchema));
ret.push(“</a>”);
}
return ret.join(”);
}

(function () {
var overrideCtx = {};

overrideCtx.Templates = {};
overrideCtx.Templates.Fields = { ‘DocIcon’: { ‘View’: CustomIcon } };
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

 

Related items field – how to access it programmatically by code?

When paying with new Workflow tasks I have noticed that they now do contain the new field of type “related items”.

This is an awesome field that allows you to add links to any items from your site collection.

By default this field exists in a new content type called Workflow Task (SharePoint 2013).

So what happens when a SharePoint 2013 workflow creates a task for an item? It fills a link to an original item that workflow has to do with in this field.

Her is how it looks like.


If you press Add related item, then

You see a nice dialog that allows you to open any item from your site collection.


Once a customer asked me to do the following logic. Once a task has been updated by someone, add comments and the guy who actually implemented the task to the original item.

So I came to a problem – how do I actually read the related items and find out what is inside?

When I looked at the fields I figured out it is actually a multiline text field


So when I wrote a short program that actually gets the value and I was surprised to see it is actually JSON!


Or in JSON.


So basically you need to add a simple parser that will read the values.

I have tried a parser which I found out in ASP.NET MVC4 but apparently it needed a couple of DLLS to be installed which we could not figure out, so I have used a NewtonSoft JSON which was added with a simple nuget package.

So the code of reading the values from related items is

using (ClientContext ctx = GetAuthenticatedContext())

{

TraceHelper.TraceInformation(ConsoleColor.Magenta, “reading related items”);

ctx.Load(ctx.Web, x=>x.ServerRelativeUrl);

ctx.ExecuteQuery();

var workflowTasksListUrl = UrlUtility.CombineUrl(ctx.Web.ServerRelativeUrl, Lists.WorkflowTasks.GetListUrl());

var workflowTasksLIst = ctx.Web.GetList(workflowTasksListUrl);

// this is just for demo, this is not the best code to work with sharpeoint items

var items = workflowTasksLIst.GetItems(

new CamlQuery()

);

ctx.Load(items);

ctx.ExecuteQuery();

string relatedItemsString = (string)items[0][BuiltInInternalFieldNames.RelatedItems];

dynamic decodedRelatedItems = JsonConvert.DeserializeObject(relatedItemsString);

foreach (var item in decodedRelatedItems)

{

int itemId = int.Parse(item.ItemId.ToString());

var listId = new Guid(string.Format(“{{{0}}}”, item.ListId.ToString()));

var webId = new Guid(string.Format(“{{{0}}}”, item.WebId.ToString()));

Console.WriteLine(“Found an item from web {0}, list {1}, itemid:{2}”,webId,listId,itemId);

}

And can be found in a demo app called “DemoAp.Reader”.

Before you can use it run DemoApp.AssetBuilder that uses spmeta2 for provisioning and builds a structure.

Source code can be found at

https://github.com/maratbakirov/2015_03_related_fieldsDemo