C# Word 2010在保存到WebDAV服务器后报告错误

C# Word 2010在保存到WebDAV服务器后报告错误,c#,asp.net-mvc-3,ms-office,webdav,C#,Asp.net Mvc 3,Ms Office,Webdav,我有一个自定义WebDAV服务器,它使用WebDAV服务器构建,驻留在ASP.NET MVC3应用程序中。这是一个.NET4.0项目 文档存储库是一个SharePoint,其中我们的MVC应用程序是它的前端,并通过WebDAV公开整个内容。请注意,我们没有在IIS 7.5上启用WebDAV发布 我已经实现了以下HTTP谓词: 获取 头部 锁定 选项 PropFind 放置 解锁 现在,当我打开word文档时,它首先处于只读模式。锁定并进入编辑模式是成功的,但当我想在文档中保存更改时,我会得到

我有一个自定义WebDAV服务器,它使用WebDAV服务器构建,驻留在ASP.NET MVC3应用程序中。这是一个.NET4.0项目

文档存储库是一个SharePoint,其中我们的MVC应用程序是它的前端,并通过WebDAV公开整个内容。请注意,我们没有在IIS 7.5上启用WebDAV发布

我已经实现了以下HTTP谓词:

  • 获取
  • 头部
  • 锁定
  • 选项
  • PropFind
  • 放置
  • 解锁
现在,当我打开word文档时,它首先处于只读模式。锁定并进入编辑模式是成功的,但当我想在文档中保存更改时,我会得到以下信息:

您的更改已保存,但由于错误而无法上载

诀窍在于文档确实正确地保存到了存储库中,我们的WebDAV服务器对word的响应是HTTP/200,但word仍然会抱怨。 我还尝试过直接从SharePoint存储库用Word编辑,只是为了确认我的办公室没有被破坏——一切正常

以下是从Word保存文档时PUT请求的响应:

HTTP/1.1 200 OK
Date: Tue, 06 Sep 2011 12:25:47 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 12.0.0.6545
Last-Modified: Tue, 06 Sep 2011 12:25:47 GMT
ETag: "{F4A63494-D302-4C9B-9C57-D0CB0937A2B0},9"
ResourceTag: rt:F4A63494-D302-4C9B-9C57-D0CB0937A2B0@00000000009
X-MSDAVEXTLockTimeout: Second-3600
Lock-Token: opaquelocktoken:{F4A63494-D302-4C9B-9C57-D0CB0937A2B0}20110906T122532Z
Expires: Mon, 22 Aug 2011 12:25:47 GMT
Cache-Control: private,max-age=0
Content-Length: 0
Public-Extension: http://schemas.microsoft.com/repl-2
Set-Cookie: WSS_KeepSessionAuthenticated=40689; path=/
下面是来自我们的WebDAV服务器对同一文档的相同响应:

HTTP/1.1 200 OK
Cache-Control: private,max-age=0
Content-Length: 0
Expires: Wed, 24 Aug 2011 08:03:28 GMT
Last-Modified: Wed, 07 Sep 2011 08:03:28 GMT
ETag: "{4a4331a8-7df6-43e6-bd5f-bb80765e83a2},1"
Server: Microsoft-IIS/7.5
MS-Author-Via: DAV
ResourceTag: rt:4a4331a8-7df6-43e6-bd5f-bb80765e83a2@00000000001
Lock-Token: opaquelocktoken:{4a4331a8-7df6-43e6-bd5f-bb80765e83a2}20110907T080328Z
X-MSDAVEXTLockTimeout: Second-3600
Public-Extension: http://schemas.microsoft.com/repl-2
MicrosoftSharePointTeamServices: 12.0.0.6545
Set-Cookie: WSS_KeepSessionAuthenticated=40689; path=/
X-Powered-By: ASP.NET
Date: Wed, 07 Sep 2011 08:03:27 GMT

因此,我尝试模拟SharePoint发出的一些标题,如MicrosoftSharePointTeamServices,但没有效果。

观察:锁定标记使用无效语法(Sharepoints也是如此)。也;这些头文件中的大多数不应该是必需的(是专有的),或者不适用于PUT响应(例如锁令牌)


我建议首先尝试使用mod_dav发布到Apache,并观察HTTP交换。

顺便说一句,我在Sphorium webdav中发现了导致这种情况的错误。错误出现在方法DavLockBase\u InternalProcessDavRequest()中,错误的代码行是:

string[] _lockTokens = this.RequestLock.GetLockTokens();
应该是:

string[] _lockTokens = this.ResponseLock.GetLockTokens();

更改后,在Word 2010中保存文件效果很好。

如果有人再次遇到此问题,下面是一个基于上述答案以及我在使用Word 2010时发现的问题而构建的修复程序。基本上,修复涉及替换“DavLockBase_InternalProcessDavRequest”方法的代码(我为每个“更正”添加了一些注释)

注意(找到一些信息):word 2010的webdav实现的行为因客户端是否安装了补丁而有所不同;因此,并非所有情况下都需要第三次修正

希望有帮助

private int DavLockBase_InternalProcessDavRequest(object sender, EventArgs e)
    {
        int _responseCode = (int)DavLockResponseCode.Ok;

        //string[] _lockTokens = this.RequestLock.GetLockTokens();
        //#1 the above line is incorrect. replaced with the following:
        string[] _lockTokens = this.ResponseLock.GetLockTokens();

        //Check to see if a lock refresh was requested
        if (base.HttpApplication.Request.Headers["If"] != null)
        {
            if (_lockTokens.Length == 1)
            {
                //#2 not sure why this should be done (or not), however I've seen this in other people corrections.
                //DavRefreshEventArgs _refreshEventArgs = new DavRefreshEventArgs(_lockTokens[0], this.RequestLock.LockTimeout);
                //OnRefreshLockDavRequest(_refreshEventArgs);
            }

            base.HttpApplication.Response.AppendHeader("Timeout", "Second-" + this.ResponseLock.LockTimeout);
        }
        else
        {
            //New lock request
            StringBuilder _opaquelockTokens = new StringBuilder();
            //#3 finally, added the check below, as most of the times, when using word 2010 there are no lock requests
            if (_lockTokens.Length > 0)
            {
                foreach (string _lockToken in _lockTokens)
                    _opaquelockTokens.Append("<opaquelocktoken:" + _lockToken + ">");

                base.HttpApplication.Response.AppendHeader("Lock-Token", _opaquelockTokens.ToString());
            }
        }

        //Check to see if there were any process errors...
        Enum[] _errorResources = this.ProcessErrorResources;
        if (_errorResources.Length > 0)
        {
            //Append a response node
            XmlDocument _xmlDocument = new XmlDocument();
            XmlNode _responseNode = _xmlDocument.CreateNode(XmlNodeType.Element, _xmlDocument.GetPrefixOfNamespace("DAV:"), "response", "DAV:");

            //Add the HREF
            XmlElement _requestLockHrefElement = _xmlDocument.CreateElement("href", "DAV:");
            _requestLockHrefElement.InnerText = base.RelativeRequestPath;
            _responseNode.AppendChild(_requestLockHrefElement);


            //Add the propstat
            XmlElement _propstatElement = _xmlDocument.CreateElement("propstat", "DAV:");
            XmlElement _propElement = _xmlDocument.CreateElement("prop", "DAV:");
            XmlElement _lockDiscoveryElement = _xmlDocument.CreateElement("lockdiscovery", "DAV:");
            _propElement.AppendChild(_lockDiscoveryElement);
            _propstatElement.AppendChild(_propElement);

            XmlElement _statusElement = _xmlDocument.CreateElement("status", "DAV:");
            _statusElement.InnerText = InternalFunctions.GetEnumHttpResponse(DavLockResponseCode.FailedDependency);
            _propstatElement.AppendChild(_statusElement);

            _responseNode.AppendChild(_propstatElement);

            base.SetResponseXml(InternalFunctions.ProcessErrorRequest(this.ProcessErrors, _responseNode));
            _responseCode = (int)ServerResponseCode.MultiStatus;
        }
        else
        {
            //No issues
            using (Stream _responseStream = new MemoryStream())
            {
                XmlTextWriter _xmlWriter = new XmlTextWriter(_responseStream, new UTF8Encoding(false));

                _xmlWriter.Formatting = Formatting.Indented;
                _xmlWriter.IndentChar = '\t';
                _xmlWriter.Indentation = 1;
                _xmlWriter.WriteStartDocument();

                //Open the prop element section
                _xmlWriter.WriteStartElement("D", "prop", "DAV:");
                _xmlWriter.WriteStartElement("lockdiscovery", "DAV:");
                this.ResponseLock.ActiveLock.WriteTo(_xmlWriter);
                _xmlWriter.WriteEndElement();
                _xmlWriter.WriteEndElement();

                _xmlWriter.WriteEndDocument();
                _xmlWriter.Flush();

                base.SetResponseXml(_responseStream);
                _xmlWriter.Close();
            }
        }

        return _responseCode;
    }
private int-DavLockBase\u InternalProcessDavRequest(对象发送方,事件参数e)
{
int _responseCode=(int)davlock responseCode.Ok;
//string[]_lockTokens=this.RequestLock.GetLockTokens();
//#1上述行不正确。替换为以下内容:
string[]_lockTokens=this.ResponseLock.GetLockTokens();
//检查是否请求了锁刷新
if(base.HttpApplication.Request.Headers[“if”]!=null)
{
if(_lockTokens.Length==1)
{
//#2不确定为什么要这样做(或不),但我在其他人身上看到了这一点。
//DavRefreshEventArgs\u refreshEventArgs=新的DavRefreshEventArgs(\u lockTokens[0],this.RequestLock.LockTimeout);
//OnRefreshLockDavRequest(_refreshEventArgs);
}
base.HttpApplication.Response.AppendHeader(“Timeout”,“Second-”+this.ResponseLock.LockTimeout);
}
其他的
{
//新锁请求
StringBuilder _opaquelockTokens=新StringBuilder();
//#3最后,添加了下面的检查,因为大多数情况下,使用word 2010时没有锁定请求
如果(_lockTokens.Length>0)
{
foreach(字符串_locktokenin _locktokes)
_opaquelockTokens.附加(“”);
base.HttpApplication.Response.AppendHeader(“锁令牌”,_opaquelockTokens.ToString());
}
}
//检查是否存在任何流程错误。。。
Enum[]\u errorResources=this.ProcessErrorResources;
如果(_errorResources.Length>0)
{
//附加响应节点
XmlDocument_XmlDocument=新的XmlDocument();
XmlNode _responseNode=_xmlDocument.CreateNode(XmlNodeType.Element,_xmlDocument.GetPrefixOfNamespace(“DAV:”,“response”,“DAV:”);
//添加HREF
XmlElement _requestLockHrefElement=_xmlDocument.CreateElement(“href”,“DAV:”);
_requestLockHrefElement.InnerText=base.RelativeRequestPath;
_responseNode.AppendChild(_requestLockhreflement);
//添加propstat
xmlement _propstatElement=_xmlDocument.CreateElement(“propstat”,“DAV:”);
xmlement _propElement=_xmlDocument.CreateElement(“prop”,“DAV:”);
xmlement _lockDiscoveryElement=_xmlDocument.CreateElement(“lockdiscovery”,“DAV:”);
_附加子项(_lockDiscoveryElement);
_propstatElement.AppendChild(_propElement);
xmlement _statusElement=_xmlDocument.CreateElement(“status”,“DAV:”);
_statusElement.InnerText=InternalFunctions.GetEnumHttpResponse(DavLockResponseCode.FailedDependence);
_propstatElement.AppendChild(_statusElement);
_responseNode.AppendChild(_propstateElement);
SetResponseXml(InternalFunctions.ProcessErrorRequest(this.ProcessErrors,_responseNode));
_responseCode=(int)ServerResponseCode.MultiStatus;
}
其他的
{
//没问题
使用(Stream _responseStream=newmemoryStream())
{
XmlTextWriter _xmlWriter=新的XmlTextWriter(_responseStream,新的UTF8Encoding(false));
_xmlWriter.Formatting=Forma