Centric connect.engage.succeed

Using CSOM to provision Column default value settings

Geschreven door Redactie Craft - 26 mei 2016

Redactie Craft
SharePoint has a lot of settings which make life a little bit easier. I want to discuss one of them. It’s about a nice little feature which makes it possible to provide default column values for all documents inside a folder or document library. Recently we were asked if it’s also possible to provision this functionality using CSOM as part of a site provisioning mechanism. The answer is “Yes”!

But first back to this setting. This can be found under the “library settings”:

Settings

After clicking it, a list of all folders inside the library is shown, as are all fields which can be configured using default values:

Default Configuration

This can be useful when you want to set a specific column value based on the folder in which you save your documents. Especially when you want to use this column within your (Office) document or you want to be able to search by the used value. Nothing new so far, but how can this be configured using CSOM? The answer is pretty simple: The configuration of these default values is saved inside the hidden “forms” folder inside the document library itself. To be exact, in the client_LocationBasedDefaults.html file:

Client Location Based Defaults

The content of this file is just a piece of xml that describes which default values are configured:

Xml Configuration

This file can easily be read using a few lines of code.

private string GetDefaultFolderValues(List sourceList)
{
    var sourceContext = (ClientContext)sourceList.Context;

    Folder formsFolder =
        sourceContext.Web.GetFolderByServerRelativeUrl(sourceList.RootFolder.ServerRelativeUrl + "/forms");

    sourceContext.Load(formsFolder, f => f.Files);
    sourceContext.ExecuteQuery();

    var clientLocationBasedDefaultsFile =
        formsFolder.Files.FirstOrDefault(
            f => f.Name.ToLowerInvariant() == "client_LocationBasedDefaults.html".ToLowerInvariant());

    if (clientLocationBasedDefaultsFile != null)
    {
        return ReadFileContent(clientLocationBasedDefaultsFile);
    }

    return null;
}

private string ReadFileContent(File file)
{
ClientResult<Stream> stream = file.OpenBinaryStream();
file.Context.ExecuteQuery();

using (StreamReader reader = new StreamReader(stream.Value, Encoding.UTF8))
{
return reader.ReadToEnd();
}
}

To apply default column values to an existing document library, you can do it the other way around:

private void SetDefaultFolderValues(List destinationList, string defaultValues)
{
    var destinationContext = (ClientContext)destinationList.Context;
    Folder formsFolder =
        destinationContext.Web.GetFolderByServerRelativeUrl(
            destinationList.RootFolder.ServerRelativeUrl + "/forms");

    var fci = new FileCreationInformation();
    fci.Content = Encoding.UTF8.GetBytes(defaultValues);
    fci.Url = "client_LocationBasedDefaults.html";
    fci.Overwrite = true;
    var metaDataFile = formsFolder.Files.Add(fci);

    destinationContext.Load(metaDataFile);
    destinationContext.ExecuteQuery();
}

Since the xml contains the relative path of the folder, you have to be sure that these paths are correct. So if you want to copy client_LocationBasedDefaults.html from one library to another, you need to replace the server relative URL like this:

public void CopyLocationBasedDefaults(List sourceList, List destinationList)
{
    string sourceDefaultValues = GetDefaultFolderValues(sourceList);

    if (sourceDefaultValues != null)
    {
        string destinationDefaultValues = Regex.Replace(
            sourceDefaultValues,
            sourceList.RootFolder.ServerRelativeUrl,
            destinationList.RootFolder.ServerRelativeUrl,
            RegexOptions.IgnoreCase);
        SetDefaultFolderValues(destinationList, destinationDefaultValues);
    }
}

This means that executing this “CopyLocationBasedDefaults” method actually provisions these default column values settings based on a “source” document library, which is pretty cool! Of course there are many other ways to construct this xml but that’s up to you.

Unfortunately, it’s not working yet! But we are getting close. The last thing we need to do is to register an event receiver which uses this configuration and applies the values to newly added files in the document library. This is a built-in event receiver called “Microsoft.Office.DocumentManagement.LocationBasedMetadataDefaultsReceiver”.

It can be activated using the following code:

public void RegisterEventReceiver(List destinationList)
{
    EventReceiverDefinitionCreationInformation erci = GetEventReceiverCreationInformation();
    EnsureEventReceiver(destinationList, erci);
}

private EventReceiverDefinitionCreationInformation GetEventReceiverCreationInformation()
{
    var erci = new EventReceiverDefinitionCreationInformation();

    erci.ReceiverName = "LocationBasedMetadataDefaultsReceiver ItemAdded";
    erci.SequenceNumber = 1000;
    erci.ReceiverClass = "Microsoft.Office.DocumentManagement.LocationBasedMetadataDefaultsReceiver";
    erci.ReceiverAssembly =
        "Microsoft.Office.DocumentManagement, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c";
    erci.EventType = EventReceiverType.ItemAdded;
    erci.Synchronization = EventReceiverSynchronization.Synchronous;

    return erci;
}

private void EnsureEventReceiver(List destinationList, EventReceiverDefinitionCreationInformation erci)
{
    var destinationContext = (ClientContext)destinationList.Context;

    destinationContext.Load(destinationList.EventReceivers);
    destinationContext.ExecuteQuery();
    var receiver = destinationList.EventReceivers.FirstOrDefault(e => e.ReceiverName == erci.ReceiverName);

    if (receiver == null)
    {
        receiver = destinationList.EventReceivers.Add(erci);
        destinationContext.Load(receiver);
        destinationContext.ExecuteQuery();
    }
}

After that, the default column values work like a charm in your document library. I added the source code as well. Have fun with it!


Tags:SharePoint

     
Schrijf een reactie
  • Captcha image
  • Verzenden