{"id":1135,"date":"2020-12-01T18:31:44","date_gmt":"2020-12-01T22:31:44","guid":{"rendered":"https:\/\/benjaminray.com\/codebase\/?p=1135"},"modified":"2020-12-01T18:35:18","modified_gmt":"2020-12-01T22:35:18","slug":"getting-latest-published-version-of-document-in-sharepoint","status":"publish","type":"post","link":"https:\/\/benjaminray.com\/codebase\/getting-latest-published-version-of-document-in-sharepoint\/","title":{"rendered":"Getting Latest Published Version of Document in SharePoint API CSOM"},"content":{"rendered":"<p>I occasionally have to use the SharePoint .Net Client-Side Object Model (CSOM) API to reach into SharePoint and poke around a little bit. It's all pretty straightforward, but something that I have not found to be straightforward is <strong>reliably<\/strong> determining which version of a file is the latest major\/published version.<\/p>\n<p>In this context, I'm usually working with a SharePoint Document Library where versioning is enabled with Major and Minor versions. The application is also using a user with administrator access to the site, which means it can view all versions of a document, including minor versions which would not normally be visible to the average end user. Lastly, I'm checking the properties of a <code>ListItem<\/code>, which may be part of a Document Library (<code>ListItemCollection<\/code>) through which I'm iterating, or which may have been loaded individually by some property (name, Id, URL, etc.)<\/p>\n<h2>Checking Latest Version Is Easy<\/h2>\n<p>If the latest version of a file happens to be a published major version, it's easy: <code>ListItem.File.Level<\/code> will be <code>FileLevel.Published<\/code>. So always start by checking that property of an item. If it's something other than <code>Published<\/code>, then you have to dig through the older versions to find the latest major\/published version (if one exists).<\/p>\n<h2>Checking Older Versions Gets Tricky<\/h2>\n<p>To see if an older version of the file is the latest major version, you can iterate through either <code>ListItem.Versions<\/code> (collection of <code>ListItemVersion<\/code>) or <code>Item.File.Versions<\/code> (collection of <code>FileVersion<\/code>). It's important to note that <code>Item.Versions<\/code> includes all versions, including the current version, while <code>Item.File.Versions<\/code> includes all file versions <strong>except<\/strong> the current version, which is already accessible through <code>Item.File<\/code>.<\/p>\n<p>But what properties should you check?<\/p>\n<h4>The IsCurrentVersion Fallacy<\/h4>\n<p>Most online resources indicate that you can simply check an older version of an item\/file to see if <code>FileVersion.IsCurrentVersion == True<\/code> or <code>ListItemVersion.IsCurrentVersion == True<\/code>, and if so, this is your latest published major version. <strong>This is not the case!<\/strong> I have found that <code>IsCurrentVersion<\/code> can be <code>True<\/code> on more than one minor version of a document.<\/p>\n<p>Before I explain that, I should point out that the current version of a document always has <code>IsCurrentVersion==True<\/code>, even if it's a minor version. This is especially important to keep in mind when you choose to iterate through the versions in <code>Item.Versions<\/code>, because the latest version (which I assume is not major\/published, otherwise you wouldn't be iterating through the versions) will have <code>IsCurrentVersion==True<\/code> even though it's not published. If iterating through <code>Item.File.Versions<\/code>, this point is moot because the latest version is not included in that collection.<\/p>\n<p>So, other than it being true on the latest version of a file (expected), and being true on the latest Major version of a file (expected), when else can it be true?<\/p>\n<p>CrazyTalk: <strong>When a document is checked out, IsCurrentVersion ==  True on the <em>second-latest<\/em> version of the file.<\/strong><\/p>\n<p>Now we have THREE possible versions in an item's version history where <code>IsCurrentVersion<\/code> can be true:<\/p>\n<ul>\n<li>Latest version (minor or major) always has <code>IsCurrentVersion==True<\/code> &larr; <em>(expected)<\/em><\/li>\n<li>Latest major version has <code>IsCurrentVersion==True<\/code>   &larr; <em>(expected)<\/em><\/li>\n<li><span style=\"background-color: #ffff00;\">2nd latest version has IsCurrentVersion==True<\/span>  &larr; <em>(WHAT?)<\/em><\/li>\n<\/ul>\n<p>Even if that second-latest version of the file is minor, or a rejected draft, etc., it will always have <code>IsCurrentVersion==True<\/code>. And there may be more scenarios where that property is unexpectedly true. As a result, I've given up on using it to help me find the latest major\/published version of a document.<\/p>\n<h4>So What's The Solution Already?<\/h4>\n<p>I've switched to using the <code>VersionId<\/code> property, which is an integer that can tell you a lot about the version you're dealing with. When you're looking at a <code>ListItemVersion<\/code> (from <code>ListItem.Versions<\/code>), the property is <code>VersionId<\/code>. And when you're looking at a <code>FileVersion<\/code> (from <code>ListItem.File.Versions<\/code>), the property is <code>Id<\/code>.<\/p>\n<p><code>VersionId<\/code> uses multiples of 512 for every major version and multiples of 1 for every minor version. The first minor version of a new document will have a <code>VersionId<\/code> of 1. Adding two more minor versions will bring the <code>VersionId<\/code> up to 3. Publishing the first major version will bring the <code>VersionId<\/code> up to 512, and adding one more minor version will bring it up to 513. The second major version will be 1024, and the next minor version will be 10125, and so on. This means there can be 511 minor versions of an item between every major version. The item with the highest <code>VersionId<\/code> that is > 0 and a multiple of 512 is the latest major\/published version.<\/p>\n<p>Alternatively, instead of the properties <code>ListItemVersion.VersionId<\/code> and <code>FileVersion.Id<\/code>, you could also look at the properties <code>ListItemVersion.VersionLabel<\/code> or <code>FileVersion.VersionLabel<\/code>. These are decimal values formatted as <em>&lt;Major&gt;.&lt;Minor&gt;<\/em>, e.g. 3.12 (Major=3, Minor=12). If the Major version > 0 and the Minor version is 0, it is a major\/published version of the file. Finding the highest non-0 Major version where the Minor version is 0 gives you the latest major (published) version of the file.<\/p>\n<p>Because <code>ListItem.Versions<\/code> returns versions in descending order, starting with the latest version, I prefer to use this (over <code>ListItem.File.Versions<\/code>). Check if each item's <code>VersionId<\/code> is > 0 and a multiple of 512 (or <code>VersionLabel<\/code> has non-0 Major version with 0 Minor version), and the first one you find matching that criteria is the latest major\/published version. You can ignore the first result if you've already checked if <code>ListItem.File.Level<\/code> is <code>FileLevel.Published<\/code>, because you already know the latest version is not major\/published. Alternatively, you could use <code>ListItem.File.Versions<\/code>, but because it returns versions in ascending order, it's a little less performant; you would have to iterate through all versions to know which is the highest.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I occasionally have to use the SharePoint .Net Client-Side Object Model (CSOM) API to reach into SharePoint and poke around a little bit. It&#8217;s all pretty straightforward, but something that  [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[27],"tags":[],"class_list":["post-1135","post","type-post","status-publish","format-standard","hentry","category-sharepoint-api"],"acf":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9GNjN-ij","jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/posts\/1135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/comments?post=1135"}],"version-history":[{"count":35,"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/posts\/1135\/revisions"}],"predecessor-version":[{"id":1170,"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/posts\/1135\/revisions\/1170"}],"wp:attachment":[{"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/media?parent=1135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/categories?post=1135"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benjaminray.com\/codebase\/wp-json\/wp\/v2\/tags?post=1135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}