Suppose that we need to check whether site collection with specified absolute url exists or not using client side object model. In OfficeDevPnP library there is convenient extension method for ClientContext WebExtensions.WebExistsFullUrl:
public static bool WebExistsFullUrl(this ClientRuntimeContext context, string webFullUrl) { bool exists = false; try { using (ClientContext testContext = context.Clone(webFullUrl)) { testContext.Load(testContext.Web, w => w.Title); testContext.ExecuteQueryRetry(); exists = true; } } catch (Exception ex) { if (IsUnableToAccessSiteException(ex) || IsCannotGetSiteException(ex)) { exists = true; } } return exists; }
Unfortunately this method works properly only within single site collection i.e. when client context (which is extended with this extension method) and url to check belong to the same managed path.
Example:
context is created from the root site http://example.com. This site has http://example.com/test sub site. In this case WebExistsFullUrl returns true for http://example.com/test url and false for some non-existent sub site's url like http://example.com/test123. I.e. behavior is correct.
But if context and url to check belong to different managed path then it always returns true.
Example:
context is created from the root site http://example.com and we call WebExistsFullUrl for some url which may belong to other site collection (e.g. which uses different managed path like http://example.com/teams/some-not-real-url. Suppose that at the moment of call we don't know whether this collection exists or not - we want to determine it by WebExistsFullUrl call). In this case WebExistsFullUrl returns true even if site collection with specified url doesn't exists.
When I analyzed the code I found the following. When we call this method with context and url which belong to the same managed path it throws exception like expected. But when it is called with context and url which belong to different managed paths exception is not thrown. Instead context is created for the root site http://example.com and method returns true and caller thinks that site exists. In order to fix this problem for different managed paths I applied the following fix in our local version:
public static bool WebExistsFullUrl(this ClientRuntimeContext context, string webFullUrl) { bool exists = false; try { using (ClientContext testContext = context.Clone(webFullUrl)) { testContext.Load(testContext.Web, w => w.Title, w => w.Url); testContext.ExecuteQueryRetry(); exists = (string.Compare(testContext.Web.Url, webFullUrl, true) == 0); } } catch (Exception ex) { if (IsUnableToAccessSiteException(ex) || IsCannotGetSiteException(ex)) { // Site exists, but you don't have access .. not sure if this is really valid // (I guess if checking if URL is already taken, e.g. want to create a new site // then this makes sense). exists = true; } } return exists; }
I.e. before to return true method also checks whether loaded url is the same as url to be checked. If they are different (which happens in scenario with different managed paths) it will return false like it should.
Described behavior was found when root site collection (http://example.com) was host-named site collection, but most probably it will also work same way for regular site collections.
This problem is also submitted to OfficeDevPnP Core issues section on GitHub: WebExtensions.WebExistsFullUrl returns true for non-existent sites from different managed path in Sharepoint 2013 on-premise.
Update 2020-11-05: this problem is fixed now in CSOM. See Call WebExtensions.WebExistsFullUrl method from OfficeDevPnP library for different site collection.
No comments:
Post a Comment