private async Task <IReadOnlyList <EntityVersion <WebResourceName, string> > > GetVersions(DateTimeRange?range, string entityType) { var entities = new List <EntityVersion <WebResourceName, string> >(); try { var responseXml = await _webDavClient.ExecuteWebDavRequestAndReadResponse( _serverUrl, "REPORT", 1, null, null, "application/xml", string.Format( @"<?xml version=""1.0""?> <C:calendar-query xmlns:C=""urn:ietf:params:xml:ns:caldav""> <D:prop xmlns:D=""DAV:""> <D:getetag/> </D:prop> <C:filter> <C:comp-filter name=""VCALENDAR""> <C:comp-filter name=""{0}""> {1} </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query> ", entityType, range == null ? string.Empty : string.Format(@"<C:time-range start=""{0}"" end=""{1}""/>", range.Value.From.ToString(s_calDavDateTimeFormatString), range.Value.To.ToString(s_calDavDateTimeFormatString)) )); XmlNodeList responseNodes = responseXml.XmlDocument.SelectNodes("/D:multistatus/D:response", responseXml.XmlNamespaceManager); // ReSharper disable once LoopCanBeConvertedToQuery // ReSharper disable once PossibleNullReferenceException foreach (XmlElement responseElement in responseNodes) { var urlNode = responseElement.SelectSingleNode("D:href", responseXml.XmlNamespaceManager); var etagNode = responseElement.SelectSingleNode("D:propstat/D:prop/D:getetag", responseXml.XmlNamespaceManager); if (urlNode != null && etagNode != null && _serverUrl.AbsolutePath != UriHelper.DecodeUrlString(urlNode.InnerText)) { var uri = new WebResourceName(urlNode.InnerText); entities.Add(EntityVersion.Create(uri, HttpUtility.GetQuotedEtag(etagNode.InnerText))); } } } catch (WebDavClientException x) { // Workaround for Synology NAS, which returns 404 insteaod of an empty response if no events are present if (x.StatusCode == HttpStatusCode.NotFound && await IsResourceCalender()) { return(entities); } throw; } return(entities); }