Sunday, July 12, 2015

Configuring metadata defaults with CSOM

SharePoint folders have had it rough the last couple of years. The internet is full of 'folders are evil' posts, but in my view folders still have their uses. One of the interesting features SharePoint folders bring to the table is automatically setting metadata. Per folder you can configure which default values fields should have. This can be a great enabler when people don't want to tag documents manually.

We wanted to use this in a recent project where we had the requirement to provision and configure this from code. The metadata defaults objects however are only available in the full trust object model, and we build for SharePoint online. That leaves us with the puzzle of what actually happens when you configure metadata defaults and figuring out if we can do the same from CSOM. We found that metadata defaults functionality is implemented through two components:

  • The 'client_LocationBasedDefaults.html' file in the forms folder of the document library
  • A feature receiver bound to the same document library


The following screenshots are from an environment that's been configured manually. We have our document library 'Metadata'. This library has two folders, 'Yes' and 'No'. A choice field with the same options is added to the library and has been configured to be set automatically for files that are added to the folders.


With SharePoint designer we can view the contents of the 'client_LocationBasedDefaults.html'. It's basically a mapping of the folder (url), the field to be set, and the field value to be set. All this in a very simple XML structure.

The event receiver can be spotted using the great tool SharePoint Manager 2013. It's interesting to note that the event receiver is part of the "Microsoft.Office.DocumentManagement" namespace, the same namespace that gives us the Document Set which is also great folder and metadata tool.

Well, this doesn't appear to be to hard to do through CSOM! First we need to create the metadata file. The hidden forms folder in the library has the interesting property that you can add files to it just as you would do to any other folder. The following snippet is all you need:
// Creating the LocationBasedDefaults file in the forms folder. Will overwrite if it is already there.
var formsFolder = ctx.Web.GetFolderByServerRelativeUrl("/Metadata/Forms/");
var fci = new FileCreationInformation();
fci.Content = Encoding.UTF8.GetBytes("<MetadataDefaults><a href=\"/Metadata/No\"><DefaultValue FieldName=\"YesNo\">No</DefaultValue></a><a href=\"/Metadata/Yes\"><DefaultValue FieldName=\"YesNo\">Yes</DefaultValue></a></MetadataDefaults>");
fci.Url = "client_LocationBasedDefaults.html";
fci.Overwrite = true;
var metaDataFile = formsFolder.Files.Add(fci);

ctx.Load(metaDataFile);
ctx.ExecuteQuery();


After this we need to bind the out of the box event receiver. Note that we explicitly configure the event receiver to be synchronous. If you don't, the user will need to refresh the screen after dragging a document to the library to see the updated value. The following snippet has all the code required for this:
//Binding the OOTB event receiver
var list = ctx.Web.Lists.GetByTitle("Metadata");
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;

var receiver = list.EventReceivers.Add(erci);
ctx.Load(receiver);
ctx.ExecuteQuery();


And that's all there is to it. It's also possible to do this with Managed Metadata values. However, to get these to work you need to ensure they're already in the taxonomy hidden list on the site you are deploying this to. That's slightly out of scope for this write-up, but let me know if you run into trouble with that.

Attached: A full demo project for a provider hosted app which creates and configures a document library with managed metadata defaults.

8 comments:

  1. Thanks for this post, Jan! It's what we need to update our huge library with the location based defaults.
    Is there a method to append rather than overwrite?

    ReplyDelete
  2. Hi beckie, 'appending' to a xml is nog possible, you would not end up with valid xml.

    You could create a .NET object that can de/serialize to the xml file. Put the existing file in to create the object with rules, add your rules to the object, and serialize again to xml.

    ReplyDelete
  3. Hi Jan, I am trying the same code with O365. The client_LocationBasedDefaults.html is updated in the O365, but the when i see the column values under "Change Default Value setting" none is updated. Can you please help me where I am missing.

    Thanks
    DJ

    ReplyDelete
  4. Hi DJ,

    the given example should work in O365. Please ensure the following;
    - The event receivers are bound, either by configuring default column values manually, or binding them through CSOM
    - The XML in client_LocationBasedDefaults.html is valid, in the right place and the values match with your site columns and folders
    - You are checking in the right place -> "list settings" -> "Column default value settings"


    It might be easiest to configure a document library the way you want manually and work backwards from there. Good luck!

    ReplyDelete
  5. Hi,

    Default column mapping is not working at all after uploading the client_LocationBasedDefaults.html file but in setting all the default value are getting stored perfectly only when i drag and drop a file default value are not getting refelected. i am using 0365

    ReplyDelete
    Replies
    1. I'm not sure I uderstand the issue. The example should work against O365.

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Could be the wrong version of the receiver assembly. The code sample has Version=15.0.0.0 and it's likely that O365 uses the same as SharePoint 2016, which is Version=16.0.0.0

    Just a thought...

    ReplyDelete

Rating