I created a Sharepoint ECB Custom Action using the (legacy) declarative paradigm of the SharePoint solution, creating a no code sandboxed solution deployed into Office 365 SharePoint site collection.
xml version="1.0" encoding="utf-8"?>
Elements xmlns="http://schemas.microsoft.com/sharepoint/">
CustomAction Id="CommonMenu.Script"
Location ="ScriptLink"
ScriptSrc="~SiteCollection/Style Library/Scripts/common.js?version=2016.02.10" />
CustomAction Id="ProBookMenu.Script"
Location ="ScriptLink"
ScriptSrc="~SiteCollection/Style Library/Scripts/xxxxxxx.js?version=2016.02.10" />
CustomAction Id="CopyAOACCAMenu.Script"
Location ="ScriptLink"
ScriptSrc="~SiteCollection/Style Library/Scripts/Copyxxxx.js?version=2016.02.10" />
CustomAction Id="CopyAOACCAMenu"
RegistrationType="ContentType"
RegistrationId="0x0120D52000259111EF1E2D4F4287A1EAC35513EC79"
Location="EditControlBlock"
Sequence="100"
Title="Copy xxx">
UrlAction Url="javascript:Copyxxx('{ListId}', {ItemId}, false)" />
CustomAction>
Elements>
To avoid that users must press CTRL + F5 when my scripts are changed, I added at the end of the ScriptSrc location a fake parameter that I’ll change when I need to update the cached script version of client browsers.
In my case I added a fake parameter named version with the reference to the script date. It’s only a convention: I could also write a random string (e.g. CiaoMamma). The important is that the new script has a reference with a different parameter from the current script.
Well, all works fine since today when, after one year, we discovered a little bug (bugs do not exist: they are only unwanted features :) ) and I’ve to update my script.
To allow this, I changed my script inside my SharePoint Solution and then I should deploy again my WSP with the new script and the Custom Action Element file updated with a new version number.
In this case, custom action definition is in the same solution of all other custom SharePoint artifacts:
- Site Fields
- Content Types
- List definitions
- List Instances
- Modules
- · …
Deploying this WSP means deploy again all the above object inside, in my case, a site collection with giga bytes of critical documents.
This operation, within SharePoint online, is a lottery!!!
Then I thought to create a very simple console application which update this parameter using CSOM (Client Side Object Model).
Using NuGet I added the SharePoint client DLL to my project (Microsoft.Sharepoint.2013.Client.16) and then I wrote this simple code.
Comments between the lines…
usingMicrosoft.SharePoint.Client;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Security;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespaceUpdateCustomAction
{
class Program
{
static voidMain(string[] args)
{
stringsiteUrl = "https://xxx.sharepoint.com/sites/xx-xx-xxxxxx";
string pwd = "yyyyy";
stringuserName = "[email protected]";
using (ClientContextclientContext = new ClientContext(siteUrl))
{
//Creating SPOnline Credentials
SecureStringsecurePassword = new SecureString();
foreach (char c inpwd.ToCharArray()) securePassword.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
//Getting SPWeb
Web web = clientContext.Web;
var userCA = web.UserCustomActions;
//Loading Web Custom Actions
clientContext.Load(userCA);
clientContext.ExecuteQuery();
//Getting the list of all custom actions with use my script as ScriptSrc
varcopyJsActions = userCA.Where(u => (u.ScriptSrc != null) && (u.ScriptSrc.ToLower().StartsWith("~sitecollection/style library/scripts/copyxxx.js"))).ToList();
foreach (varcopyJsAction in copyJsActions)
{
//Replecing the version parameter
string s = copyJsAction.ScriptSrc;
string s1 = s.Substring(0, s.LastIndexOf("?"));
string res = $"{s1}?version=2017.01.19";
copyJsAction.ScriptSrc = res;
//Update the custom action
copyJsAction.Update();
clientContext.ExecuteQuery();
}
if(copyJsActions.Count == 0)
{
Console.WriteLine("Custom Action not found");
}
Console.ReadLine();
}
}
}
}