我正在尝试在NWebDAV和 ASP.NET Core 3.1 之上实现自定义 CardDAV 服务器,使用现有数据库作为联系人的实际数据源。(NWebDAV 似乎对基本的 WebDAV 概念有很好的支持,比如响应PROPFIND
。开箱即用,运行它的示例项目来服务你的主目录似乎工作得很好。OTOH,像这样的东西REPORT
显然丢失了,我还不确定如何很多工作要做。)
我使用 iOS 13 作为我的主要测试客户端。
我已经成功地将它:
- 将我的服务器添加为帐户时通过“验证”(包括基本身份验证)
- 在“通讯录”应用的“组”视图中显示我正在服务的多个通讯簿
所以我知道它正在解析我的PROPFIND
回答。但后来,什么都没有。据我了解,它应该向我的服务器发出某种REPORT
请求,要么首先进行完全同步,要么——在搜索字段中输入内容时——查询特定联系人。它似乎永远不会尝试。
我给它类似的东西:
<addressbook-home-set xmlns="urn:ietf:params:xml:ns:carddav">
<D:href>/addressbooks/sample/108</D:href>
<D:href>/addressbooks/sample/109</D:href>
</addressbook-home-set>
它会PROPFIND
针对每个地址簿发出请求,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<A:propfind xmlns:A="DAV:">
<A:prop>
<A:add-member />
<E:bulk-requests xmlns:E="http://me.com/_namespace/" />
<A:current-user-privilege-set />
<A:displayname />
<E:guardian-restricted xmlns:E="http://me.com/_namespace/" />
<D:max-image-size xmlns:D="urn:ietf:params:xml:ns:carddav" />
<D:max-resource-size xmlns:D="urn:ietf:params:xml:ns:carddav" />
<C:me-card xmlns:C="http://calendarserver.org/ns/" />
<A:owner />
<C:push-transports xmlns:C="http://calendarserver.org/ns/" />
<C:pushkey xmlns:C="http://calendarserver.org/ns/" />
<A:quota-available-bytes />
<A:quota-used-bytes />
<A:resource-id />
<A:resourcetype />
<A:supported-report-set />
<A:sync-token />
</A:prop>
</A:propfind>
我对此作出如下回应:
<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:">
<D:response>
<D:href>http://localhost:55946/addressbooks/sample/108</D:href>
<D:propstat>
<D:prop>
<D:add-member />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}add-member is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<bulk-requests xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}bulk-requests is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<guardian-restricted xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}guardian-restricted is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-image-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-image-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-resource-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-resource-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:owner />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}owner is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<push-transports xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}push-transports is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<pushkey xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}pushkey is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-available-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-available-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-used-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-used-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:resource-id />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}resource-id is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:sync-token />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}sync-token is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:current-user-privilege-set>
<D:privilege>
<D:read />
</D:privilege>
<D:privilege>
<D:read-acl />
</D:privilege>
<D:privilege>
<D:read-current-user-privilege-set />
</D:privilege>
<D:privilege>
<D:write />
</D:privilege>
<D:privilege>
<D:bind />
</D:privilege>
</D:current-user-privilege-set>
<D:displayname>SampleContacts108</D:displayname>
<me-card xmlns="http://calendarserver.org/ns/">
<D:href>/addressbooks/sample/108/contact-49191/</D:href>
</me-card>
<D:resourcetype>
<D:collection />
<addressbook xmlns="urn:ietf:params:xml:ns:carddav" />
</D:resourcetype>
<D:supported-report-set>
<D:supported-report>
<addressbook-query xmlns="urn:ietf:params:xml:ns:carddav" />
</D:supported-report>
<D:supported-report>
<addressbook-multiget xmlns="urn:ietf:params:xml:ns:carddav" />
</D:supported-report>
<D:supported-report>
<D:expand-property />
</D:supported-report>
</D:supported-report-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://localhost:55946/addressbooks/sample/108/Bar,Foo</D:href>
<D:propstat>
<D:prop>
<D:add-member />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}add-member is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<bulk-requests xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}bulk-requests is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:current-user-privilege-set />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}current-user-privilege-set is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<guardian-restricted xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}guardian-restricted is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-image-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-image-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-resource-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-resource-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<me-card xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}me-card is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:owner />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}owner is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<push-transports xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}push-transports is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<pushkey xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}pushkey is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-available-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-available-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-used-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-used-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:resource-id />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}resource-id is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:resourcetype />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}resourcetype is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:supported-report-set />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}supported-report-set is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:sync-token />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}sync-token is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:displayname>Bar, Foo</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
(我已经实现me-card
了,因为有人说不这样做可能会使 iOS 联系人崩溃,并希望它会提示 iOS至少尝试获取我的卡片。但是,唉。)
此响应包括地址簿本身的元数据以及其中的示例联系人。我不确定这是否正确,但离开那个联系似乎并没有改变任何事情。
我支持报告addessbook-query
和addressbook-multiget
. 我对规范中的8. Address Book Reports的阅读是,这应该足以符合标准。
让我感到困惑的是,只有……什么都没有。没有面向用户的错误,没有进一步的请求等。
我确实在控制台中找到了一些东西:
com.apple.dataaccess debug 10:52:13.523530+0200 dataaccessd <private>: There are no server side items to grab, so I'm outta here
但我不知道这是否指的是这个帐户(可能是不同的服务器)。如果是这样,我很想知道是什么让 iOS 得出了这个结论?
所以,我的主要问题是:我是否有基本假设正确,即 CardDAV 客户端最终应该发出REPORT
查询联系人的请求?