上篇文章 http://www.cnblogs.com/jianyi0115/archive/2007/03/16/677712.html
讲述了如何通过iis的webdav支持实现客户端的office直接编辑服务器上的文件,
本篇将讲解如何实现客户端的office直接编辑数据库中的二进制形式保存的office文件。

实现的关键:模拟IIS,自己实现一个webdav的服务器端。

首先,我们简单了解一下webdav:
webdav,中文可以翻译为网络分布式协作协议,它解决了http协议中一个问题:http无法实现版本和单访问控制。
什么是单访问控制呢?假设我们有一个页面编辑某条数据,这个页面可以同时被多个用户使用,那么最终的数据是最后一个用户提交的数据,
而其他用户是不知道的.我们的99%的web程序都存在此问题,当然通过编码可以解决,但http协议本身并没有提供对这种情形的支持。

webdav协议在标准的http协议的基础上,扩展了以下请求动作(verb):
PUT:用于客户端推送二进制文件。(好像http有这个verb)
LOCK:用户锁定一个资源,保证资源的单访问
UNLOCK:解锁一个资源
OPTIONS:获取服务器可以支持的请求类型
DELETE:删除服务器文件
PROPFIND:查询文件属性
其他动作: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
要详细地了解webdav,大家可以google一下,或访问http://en.wikipedia.org/wiki/WebDAV

笔者在实现这个解决方案的时候,是采用fiddler,debug IE的http请求,才搞懂了IIS本身的实现机制,为了形象化,可以看一下webdav请求相应的
数据:
发起一个OPTIONS请求
OPTIONS /PMDemo/Test/待办事务.doc HTTP/1.1
User-Agent: Fiddler
Host: localhost

响应如下:
HTTP/1.1 200 OK
Date: Wed, 27 Dec 2006 11:34:03 GMT
Server: Microsoft-IIS/6.0
MicrosoftOfficeWebServer: 5.0_Pub
X-Powered-By: ASP.NET
MS-Author-Via: DAV
Content-Length: 0
Accept-Ranges: bytes
DASL: <DAV:sql>
DAV: 1, 2
Public: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
Allow: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, COPY, MOVE, PROPFIND, PROPPATCH, SEARCH, LOCK, UNLOCK
Cache-Control: private

搞清楚了这些,下面我们的任务就是如何在asp.net中实现一个wevdav服务器.
显然,这要求我们需要在底层截获http请求,幸运的是asp.net中支持这种技术:HttpHandler.它可以让我们自己的代码来处理http请求.

首先,我们在web.config中做如下配置:

    <httpHandlers>
            <remove verb="*" path="*"/>            
            <add verb="GET,PUT,UNLOCK,LOCK,OPTIONS" path="*.doc,*.xml" type="Webdav.WebdavProtocolHandler,Webdav"/>
     </httpHandlers>

通过这个配置,使我们的WebdavProtocolHandler可以来处理webdav请求.

WebdavProtocolHandler类是一个标准的httphandler,实现了IHttpHandler接口,它按照客户端的请求类型,返回符合wevdav协议的数据.

WebdavProtocolHandler类需要按照不同的webdav请求动作,做不同的处理,那么怎么来实现这个类呢?
这里就要用到一个设计模式:命令模式.

首先定义一个接口:

public interface IVerbHandler
{
      void Process( HttpContext context );
}

实现对Options请求的处理:

class OptionsHandler : IVerbHandler
    {
        #region IVerbHandler 成员

public void Process(System.Web.HttpContext context)
        {
            context.Response.AppendHeader("DASL", "<DAV:sql>");
            context.Response.AppendHeader("DAV", "1, 2");

context.Response.AppendHeader("Public", "OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH");

context.Response.AppendHeader("Allow", "OPTIONS, TRACE, GET, HEAD, DELETE, PUT, COPY, MOVE, PROPFIND, PROPPATCH, SEARCH, LOCK, UNLOCK");
        }

#endregion
    }

webdav的请求verb多达15个以上,大多数情况下,我们并不需要一个完整的webdav支持,故我们只要对其中的几个进行实现即可。

实现对LOCK的支持:

 class LockHandler : IVerbHandler
    {
        #region IVerbHandler 成员

public void Process(System.Web.HttpContext context)
        {
            context.Response.ContentType = "text/xml";

string token = Guid.NewGuid().ToString() + ":" + DateTime.Now.Ticks.ToString() ;

context.Response.AppendHeader("Lock-Token", "<opaquelocktoken:" + token + ">");
          
            string xml = @"<?xml version=""1.0""?>
<a:prop xmlns:a=""DAV:""><a:lockdiscovery>
<a:activelock><a:locktype><a:write/></a:locktype>
<a:lockscope><a:exclusive/></a:lockscope><owner xmlns=""DAV:"">Administrator</owner><a:locktoken>
<a:href>opaquelocktoken:{0}</a:href></a:locktoken>
<a:depth>0</a:depth><a:timeout>Second-180</a:timeout></a:activelock></a:lockdiscovery>
</a:prop>";

context.Response.Write( String.Format( xml , token ) );
            context.Response.End();
        }

#endregion
    }

注意这篇文章的主题:实现在线编辑。并没有版本控制等其他内容,大家仔细看以上的代码,服务器并没有真正实现"锁定",只是假装告诉客户端,你要的资源已经给你锁定了,你可以放心的编辑了。当然,有兴趣的朋友可以实现真正的锁定,无非可以通过给数据做一个状态字段来实现。但注意,要考虑一些复杂的情况,如自动解锁(用户打开一个文档,然后关机了,文档岂不永远锁定了?)等等。

接着,我们实现UNLOCK,同样是假的:

class UnLockHandler : IVerbHandler
    {
        #region IVerbHandler 成员

public void Process(System.Web.HttpContext context)
        {            
        }

#endregion
    }

下面,我们将实现两个最重要的请求动作的处理:Get和Put, office请求打开一个服务器上的文件时,采用get请求,office保存一个文件到服务器上时,发送put请求。

首先,我们要考虑一种数据项标识的传递策略,即:客户端发起访问数据库的office文件行,那么如何确认数据行的主键?
有两种策略:
1)通过不同的文件名 , 如,请求http://localhost/weboffice/1.doc  这个请求主键 为1的文件。
2)通过文件路径, 如,请求http://localhost/weboffice/1/文件名.doc  这个请求主键为1的文件。
我们将采用策略2。

再返回到我们对web.config做的配置:

<add verb="GET,PUT,UNLOCK,LOCK,OPTIONS" path="*.doc,*.xml" type="Webdav.WebdavProtocolHandler,Webdav"/>

这个配置允许WebdavProtocolHandler处理所有对doc和xml的请求处理,为什么要允许xml呢,因为office2003之后,支持xml格式,可以直接在
数据库重以xml的格式存放office文件。

接着,我们要确认我们的数据存储结构,即,office文件在数据库中时如何存放的。

我们有一个附件表:Document

CREATE TABLE [dbo].[Document] (
    [DocumentId] [int] IDENTITY (1, 1) NOT NULL ,
    [Name] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [Description] [text] COLLATE Chinese_PRC_CI_AS NULL ,
    [CreateTime] [datetime] NULL ,
    [Size] [int] NULL ,
    [CreatorId] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [CreatorName] [char] (10) COLLATE Chinese_PRC_CI_AS NULL ,
    [CreateYear] [int] NULL ,
    [ContentType] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [DeptId] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [DeptName] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [Content] [image] NULL ,
    [ModifyTime] [datetime] NULL ,
    [OwnerType] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [TemplateAble] [bit] NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

设计一个文裆实体:

    [Serializable]
   public class Document
   {
       public Document()
       { }

static public Document FromPostFile(System.Web.HttpPostedFile file , User user )
       {
           Document doc = new Document(file);
           doc.CreateTime = DateTime.Now;
           doc.CreatorId = user.Id;
           doc.CreatorName = user.Name; 
           doc.DeptId = user.OrgId;
           doc.DeptName = user.OrgName;
           return doc;
       }

public Document(System.Web.HttpPostedFile file)
        {
            string[] strs = file.FileName.Split( '\\' );
            this.Name = strs[strs.Length - 1];
            Size = file.ContentLength;
            //读取文件的数据
            this.Content = new byte[Size];
            Stream fileDataStream = file.InputStream;
            fileDataStream.Read( this.Content , 0, Size );
            ContentType = file.ContentType;
        }

private int _DocumentId;
      /// <summary>
      ///   任务名
      /// </summary>
      private string _Name;
      /// <summary>
      ///   任务描述
      /// </summary>
      private string _Description;
      /// <summary>
      ///   报表创建时间
      /// </summary>
      private DateTime _CreateTime = DateTime.Now ;
      private int _Size = 0 ;
       private byte[] _Data;
      /// <summary>
      ///   创建人Id
      /// </summary>
      private string _CreatorId;
      /// <summary>
      ///   创建人名
      /// </summary>
      private string _CreatorName;

private int _CreateYear;
      private string _ContentType;
      /// <summary>
      ///   部门ID(便于统计)
      /// </summary>
      private string _DeptId;
      /// <summary>
      ///   部门名
      /// </summary>
      private string _DeptName;   
      // Property DocumentId
      public int DocumentId   
      {
         get
         {
            return _DocumentId;
         }
         set
         {
            this._DocumentId = value;
         }
      }      
      // Property Name
      public string Name   
      {
         get
         {
            return _Name;
         }
         set
         {
             this._Name = value;
         }
      }      
      // Property Description
      public string Description   
      {
         get
         {
            return _Description;
         }
         set
         {
             this._Description = value;
         }
      }      
      // Property CreateTime
      public DateTime CreateTime   
      {
         get
         {
            return _CreateTime;
         }
         set
         {
            this._CreateTime = value;
         }
      }
       private DateTime _ModifyTime = DateTime.Now;
       public DateTime ModifyTime
       {
           get
           {
               return _ModifyTime;
           }
           set
           {
               this._ModifyTime = value;
           }
       }      
      // Property Size
      public int Size   
      {
         get
         {
            return _Size;
         }
         set
         {
            this._Size = value;
         }
      }      
      // Property Data
      public byte[] Content   
      {
         get
         {
            return _Data;
         }
         set
         {
            this._Data = value;
         }
      }      
      // Property CreatorId
      public string CreatorId   
      {
         get
         {
            return _CreatorId;
         }
         set
         {
            this._CreatorId = value;
         }
      }

// Property CreatorName
      public string CreatorName
      {
          get
          {
              return _CreatorName;
          }
          set
          {
              this._CreatorName = value;
          }
      }      
      // Property CreateYear
      public int CreateYear   
      {
         get
         {
            return _CreateYear;
         }
         set
         {
            this._CreateYear = value;
         }
      }      
      // Property ContentType
      //application/msword
      //text/plain
      public string ContentType   
      {
         get
         {
            return _ContentType;
         }
         set
         {
             this._ContentType = value;
         }
      }

// Property DeptId
      public string DeptId
      {
          get
          {
              return _DeptId;
          }
          set
          {
              if (this._DeptId != value)
                  this._DeptId = value;
          }
      }
      // Property DeptName
      public string DeptName
      {
          get
          {
              return _DeptName;
          }
          set
          {
              this._DeptName = value;
          }
      }

private string _Type;
       public string OwnerType
       {
           get
           {
               return _Type;
           }
           set
           {
               this._Type = value;
           }
       }
       private bool _TemplateAble;
      /// <summary>
      /// 是否可以作为模版
      /// </summary>
       public bool Templateable
       {
           get
           {
               return _TemplateAble;
           }
           set
           {
               this._TemplateAble = value;
           }
       }
       public override string ToString()
       {
           return Encoding.UTF8.GetString(this.Content);
       }

public static Document FromString(string s, User user)
       {
           Document doc = new Document();
           doc.CreateTime = DateTime.Now;
           doc.CreatorId = user.Id;
           doc.CreatorName = user.Name;
           doc.DeptId = user.OrgId;
           doc.DeptName = user.OrgName;
           doc.Content = Encoding.UTF8.GetBytes(s);
           doc.Size = doc.Content.Length;
           doc.ContentType = "text/plain";
           return doc;
       }
      public static string ByteToString( byte[] bytes )
      {
          return Encoding.UTF8.GetString( bytes );
      }
       public static byte[] StringToByte(string s)
       {
           return Encoding.UTF8.GetBytes(s); 
       }
       public string GetExtendName()
       {
           string[] arr = this.Name.Split( '.' );

if (arr.Length < 1) return "";
           else return arr[ arr.Length - 1 ];
       }   
   }

考虑到数据操作逻辑的可变性,不同的项目里面附件表设计的不同,这里引入一个数据操作接口:

public interface IWebdavDocumentHandler
{
        Document GetDocument(int id);//获取文档数据
        void ModifyDocContent(int docId, byte[] data);//修改文档内容
}

具体的实现这里就不写了。

好了,我们的数据访问逻辑已经有了,那么首先看get动作处理的实现:

    class GetHandler : IVerbHandler
    {
        #region IVerbHandler 成员
        public void Process(System.Web.HttpContext context)
        {
            int id = WebdavProtocolHandler.GetDocumentId( context ); //获取到主键

IWebdavDocumentHandler docSvr = new DefaultWebdavDocumentHandler(); //修改此处代码,实现不同的数据操作逻辑,可引入工厂模式
            Document doc = docSvr.GetDocument(id);

if (doc == null)
            {
                context.Response.Write("文档不存在!");
                return;
            }

context.Response.Clear();
            context.Response.ContentType = doc.ContentType;
            //下载文件名限制32字符 16 汉字
            int maxlength = 15;
            string fileName = doc.Name; //att.FileName ;
            if (fileName.Length > maxlength)
            {
                fileName = "-" + fileName.Substring(fileName.Length - maxlength, maxlength);
            }

fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8); //必须编码,不然文件名会出现乱码
            context.Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName + "");

if (doc.Content != null && doc.Content.Length > 0)
                context.Response.BinaryWrite(doc.Content);

context.Response.End();
        }
        #endregion
    }

很简单吧,跟我们普通实现文档下载的代码一样。

put动作的实现:

 class PutHandler : IVerbHandler
    {
        #region IVerbHandler 成员

public void Process(System.Web.HttpContext context)
        {
            int docId = WebdavProtocolHandler.GetDocumentId(context);

Document doc = GetDocFromInput(context.Request);

doc.DocumentId = docId;

IWebdavDocumentHandler docSvr = new DefaultWebdavDocumentHandler(); //修改此处代码,实现不同的数据操作逻辑,可引入工厂模式

docSvr.ModifyDocContent( doc.DocumentId , doc.Content );
        }

private Document GetDocFromInput(System.Web.HttpRequest request )
        {
            Document doc = new Document();
            //读取文件的数据
            doc.Content = new byte[ request.ContentLength ];
            doc.Size = request.ContentLength;
            Stream fileDataStream = request.InputStream;
            fileDataStream.Read( doc.Content , 0, doc.Size );
            doc.ContentType = request.ContentType;
            return doc;
        }
        #endregion
    }

OK,主要的动作都实现了,下面,我们需要WebdavProtocolHandler将各命令处理对象整合到一起:

    public class WebdavProtocolHandler : IHttpHandler
    {
        public static int GetDocumentId( HttpContext context )//按照前面确定的主键策略返回主键
        {
            string url = context.Request.Url.ToString();
            string[] arr = url.Split( '/' );
            string id = arr[arr.Length - 2];
            return Convert.ToInt32( id );
        }
        public void ProcessRequest(HttpContext context)
        {
            HttpRequest Request = context.Request;
            context.Response.AppendHeader("OpenWebDavServer", "1.0");
            string verb = Request.HttpMethod;
            //Log.Write(verb);
            IVerbHandler vh = GetVerbHandler( verb );

if( vh == null )
                return ;

vh.Process(context);      
        }

private IVerbHandler GetVerbHandler(string verb)
        {
            switch (verb)
            {
                case "LOCK" :
                    return new LockHandler();
                case "UNLOCK":
                    return new UnLockHandler();
                case "GET":
                    return new GetHandler();
                case "PUT":
                    return new PutHandler();               
                case "OPTIONS":
                    return new OptionsHandler();
                default :
                    return null;
            }
        }    
        public bool IsReusable
        {
            get { return false; }
        }
    }

到这里呢,已经基本上算game over了,基于以上代码设计,可以完全实现office文档的在线编辑。若要通过链接直接打开编辑,可以
采用Office文档在线编辑的实现之一的Document_Edit2函数触发office编辑。

哦,IIS还需要做一点小配置:
1)将.doc , .xml 加入到站点虚拟目录的isapi映射, 不要选中 "确认文件是否存在",动作要选全部动作,
2)禁用IIS本身的Webdav扩展,
3)删除虚拟目录HTTP头中的自定义HTTP头: MicrosoftOfficeWebServer,如果有的话。

this is the real end.

分类: 企业级开发, Office开发
标签: office, 在线编辑
绿色通道:好文要顶关注我收藏该文与我联系
jianyi
关注 - 5
粉丝 - 65
+加关注

0
0
(请您对文章做出评价)

« 博主前一篇:DBO -- 实体设计 -- 对象关联还是ID关联
» 博主后一篇:Enable MOSS Show Detail Error Message On Page

posted on 2007-07-15 10:38 jianyi 阅读(8087) 评论(62) 编辑 收藏


FeedBack:

2201821
#1楼 2007-07-15 13:05 风云      
不错,好文章!
 回复 引用 查看   

#2楼 2007-07-15 13:22 Join miao      
好长。。。
 回复 引用 查看   

#3楼 2007-07-15 13:23 Join miao      
辛苦了
 回复 引用 查看   

#4楼[楼主] 2007-07-15 13:58 jianyi0115      
@Join miao
哈哈,代码都贴上来了,所以长了。
 回复 引用 查看   

#5楼 221.219.62.*  2007-07-15 17:30 天天基金网[未注册用户]
hao
 回复 引用   

#6楼 2007-07-15 19:20 过江      
好.
 回复 引用 查看   

#7楼 220.207.104.*  2007-07-15 19:56 goo[未注册用户]
您好!

我按照你提供的方法编写代码,并编译通过,但当word打开一个文件时,是只读状态,无法编辑后再保存到服务器。

测试环境为:Asp.net 2.0,windows xp sp2, office 2003
 回复 引用 

#8楼[楼主] 2007-07-15 22:04 jianyi0115      
@goo
删除虚拟目录HTTP头中的自定义HTTP头: MicrosoftOfficeWebServer
这个做了吗?
若有MicrosoftOfficeWebServer头的话,office会认为是IIS默认的webdav
实现,会发送额外的命令,而我们对这些命令是没有处理的。
 回复 引用 查看   

#9楼 125.74.85.*  2007-07-15 23:05 laoda[未注册用户]
微软有个ocx控件可以嵌入office,有网友扩展了它让他可以二进制形式保存回服务器,因为是控件所以可以嵌入到网页中,可控制性比较强,因该比这样做好点。
 回复 引用   

#10楼 125.74.85.*  2007-07-15 23:10 laoda[未注册用户]
该ocx该控件微软提供了c++源代码,所以可方便的进行扩展.
 回复 引用   

#11楼[楼主] 2007-07-15 23:17 jianyi0115      
@laoda
知道有这样一个ocx,我的方案是纯.net实现,直接激活客户端的office,微软的
sharepoint的文档管理也是这么处理的。
 回复 引用 查看   

#12楼 2007-07-16 07:32 布尔      
原来一直在用金格的控件,可以考虑自己来实现了,呵呵,不过又想到一个问题,比如要做签章是不是还得用控件呢
 回复 引用 查看   

#13楼 58.214.240.*  2007-07-16 08:35 goo[未注册用户]
@jianyi0115
没有HTTP头: MicrosoftOfficeWebServer

我的调用代码为:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>无标题页</title>
<script language="javascript" type="text/javascript">
var __OpenDocuments = null ;

function documentEdit( url )
{
if( __OpenDocuments == null ) {
try{
__OpenDocuments = new ActiveXObject("SharePoint.OpenDocuments.3"); //for office 2007
}
catch(e){}

if( __OpenDocuments == null || typeof(__OpenDocuments) == "undefined" ) {
try{
__OpenDocuments = new ActiveXObject("SharePoint.OpenDocuments.2"); //for office 2003
}
catch(e){}
}

if( __OpenDocuments == null || typeof(__OpenDocuments) == "undefined" ) {
alert( "请安装Word(2003或更高版本)" );
return ;
}
}
var result = __OpenDocuments.EditDocument( url , "Word.Document" );

if( result == false ) {
alert( "无法打开文档." );
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<input type="button" value="打开文档" οnclick="documentEdit('http://localhost/Office/1/1.doc');return false;" />
</div>
</form>
</body>
</html>
 回复 引用 

#14楼[楼主] 2007-07-16 11:18 jianyi0115      
@布尔
这个方案跟签章没有直接的关系的,签章的内容应该在文档里面吧,那会
自动保存到服务器上的。但客户端还是要用签章控件的。
 回复 引用 查看   

#15楼 58.218.171.*  2007-07-16 11:39 娃娃鱼
好东西,自己做一些简单的在线编辑应该还是不错的。
不喜欢用ACTIVEX控件的方式实现,这个真的不错。
研究一下。谢谢
 回复 引用   

#16楼 219.142.169.*  2007-07-16 11:46 jisen[未注册用户]
记住了!有时间仔细研究一下!
 回复 引用   

#17楼[楼主] 2007-07-16 11:47 jianyi0115      
@goo
我的测试环境为测试环境为:
Asp.net 2.0,windows 2003 sp1, office 2003或2007
建议用fiddler debug下http请求,可以比照一下IIS本身实现的webdav和
自己实现的在处理时有什么差别。
 回复 引用 查看   

#18楼 58.214.240.*  2007-07-16 12:03 goo[未注册用户]
@jianyi0115

是否能提供完整代码?
 回复 引用 

#19楼[楼主] 2007-07-16 14:36 jianyi0115      
@goo
这个是在一个项目中的方案,完整代码不方便提供的,有时间整理一下。
其实,所有的代码文章里都有了~
 回复 引用 查看   

#20楼 2007-07-16 16:49 ColdDog      
@goo
我也是就这点要求,方便研究
 回复 引用 查看   

#21楼 2007-07-16 17:38 rex,xiang      
有价值,收藏了
 回复 引用 查看   

#22楼 58.214.240.*  2007-07-17 10:57 goo[未注册用户]
@jianyi0115
怎样通过编程发起一个OPTIONS请求
 回复 引用   

#23楼[楼主] 2007-07-17 12:13 jianyi0115      
@goo
发起一个普通的http请求,在头信息中添加OPTIONS.用到类HttpWebRequest
 回复 引用 查看   

#24楼 58.214.240.*  2007-07-17 13:41 goo[未注册用户]
@jianyi0115

Word客户端打开服务器上一个文件,修改后再保存至服务器,这样一个过程具体怎么实现。
 回复 引用 

#25楼[楼主] 2007-07-17 16:07 jianyi0115      
@goo
Word客户端发送http请求服务器上一个文件:http://some/some/some.doc; 这里some.doc不是一个具体的文件,实际上对应一个httpHandler,some.doc返回doc流到word;
修改后保存,Word客户端会采用put方法,将所有文档内容发送到服务器端
,服务器端进行相应处理。

说白了,跟http基本是一回事。

 回复 引用 查看 

#26楼 58.214.240.*  2007-07-18 10:05 goo[未注册用户]
@goo
那Word客户端怎么发起一个OPTIONS请求呢???
 回复 引用   

#27楼 2007-07-20 13:45 Clark Zheng      
mark
 回复 引用 查看   

#28楼[楼主] 2007-07-20 19:45 jianyi0115      
@goo
Word客户端发起一个OPTIONS请求只能通过发送http请求来实现吧。
 回复 引用 查看   

#29楼 220.163.86.*  2007-11-22 13:39 老D[未注册用户]
我按博主的方法写了一个,成功实现,谢谢!

因为对WebDav不太懂,就想当然地没有写LockHandle.结果从数据库里读出来的文档变成了只读.想了两天都没想明白是为什么,我还把Http头截下来对比,看是出了什么问题.最后把LockHandle写了就没问题了,呵呵.

但是权限的问题没有办法解决.怎样控件文档打开的权限啊?

博主,能请教你的MSN.QQ或Email吗? 还有其它问题向您请教,谢谢!
 回复 引用 

#30楼 222.212.92.*  2008-01-09 22:03 天天基金[未注册用户]
非常感谢,正找这东西,
 回复 引用   

#31楼[楼主] 2008-03-03 21:52 jianyi0115      
@天天基金
项目中用到的朋友可以下个http debug(如Fiddler)工具,实际跟踪一下word发出的http请求,很多问题都可以解决了。
 回复 引用 查看   

#32楼 202.214.4.*  2008-04-14 14:11 小瑞22[未注册用户]
出问题了,老大。
word端启用编辑,第一个请求就出错了。
如果禁用 iis5的 webdav,OPTIONS请求后,对应得response是错误页,提示
访问存取失败,不能执行cgi等程序。
如果不禁用iis5的webdav,一切正常。
如果用.net自己的webserver,一切正常。
是不是iis的版本问题呢

 回复 引用 

#33楼 202.214.4.*  2008-04-14 14:22 msn: rui.star@126.com mail:vstarcn@gmail.com[未注册用户]
博主你好,看了你得word在线编辑之实现,我在visual studio的webserver下调试,完全正常,但是在iis5下禁用webdav服务后,调试出错。用fiddler跟踪,发现
OPTIONS /project/ProjectDocument/Using/97b39ac0-310a-4c5d-8f2d-ef82d126a8c4/732/746/774/366fe193-4aa1-46a4-ac24-1843ace750ec.xls HTTP/1.1
Translate: f
User-Agent: Microsoft Data Access Internet Publishing Provider Protocol Discovery
Host: localhost
Content-Length: 0
Proxy-Connection: Keep-Alive
Pragma: no-cache
这个请求的返回response是一个html出错文本,主要错误信息:
HTTP 403.1 禁止访问:禁止可执行访问。您试图从目录中执行CGI、ISAPI 或其他可执行程序,但该目录不允许执行程序
从而导致无法在iis5上在线编辑。iis5所有权限都给了,并且在开启默认webdav的情况下,可以在线编辑。(当然,不走咱们的自定义httpmodle).
试了很久,还请博主指点。
msn: rui.star@126.com mail:vstarcn@gmail.com
 回复 引用   

#34楼[楼主] 2008-04-14 22:24 jianyi      
@小瑞22
我开发的时候用的是IIS6,IIS5就不知道了,估计跟IIS6的机制不一样,你可以试试看能不能把Webdav的Verb(如OPTIONS ,Put)映射到asp.net的处理程序。
 回复 引用 查看   

#35楼[楼主] 2008-04-14 22:27 jianyi      
@msn: rui.star@126.com mail:vstarcn@gmail.com
试试看能不能把Webdav的Verb(如OPTIONS ,Put)映射到asp.net的处理程序。
 回复 引用 查看   

#36楼 202.214.4.*  2008-04-15 10:19 msn: rui.star@126.com [未注册用户]
感谢jianyi博主的无私帮助。
问题已经解决。 我抛弃iis5了。哈哈。
这两篇文章相当有价值。
 回复 引用   

#37楼 124.84.204.*  2008-04-18 15:07 瑞rui.star@126.com [未注册用户]
jianyi兄,我实现LOCK,但是返回的RESPONSE不能使WORD弹出只读编辑那个对话框.我跟默认的IIS的LOCK对比如下:
--我模拟的lock,这样word没有任何反应?--------------

HTTP/1.1 200 OK
Date: Fri, 18 Apr 2008 06:26:42 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
OpenWebDavServer: 1.0
HTTP/1.1: 423 Locked
Connection: close
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Content-Length: 404

<?xml version="1.0"?>
<a:prop xmlns:a="DAV:"><a:lockdiscovery>
<a:activelock><a:locktype><a:write/></a:locktype>
<a:lockscope><a:exclusive/></a:lockscope><owner xmlns="DAV:">guest</owner><a:locktoken>
<a:href>opaquelocktoken:eb56e920-3483-442a-a8b3-188c0394ab15:633441292022031250</a:href></a:locktoken>
<a:depth>0</a:depth><a:timeout>Second-180</a:timeout></a:activelock></a:lockdiscovery></a:prop>

---IIS自己的webdav的正确的Lock

HTTP/1.1 423 Locked
Connection: close
Date: Fri, 18 Apr 2008 06:35:12 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Type: text/xml
Content-Length: 396

<?xml version="1.0"?><a:prop xmlns:a="DAV:"><a:lockdiscovery><a:activelock><a:locktype><a:write/></a:locktype><a:lockscope><a:exclusive/></a:lockscope><owner xmlns="DAV:">Administrator</owner><a:locktoken><a:href>opaquelocktoken:B23DB6F1-294B-424C-9EFD-A64DC4402030:214748364852</a:href></a:locktoken><a:depth>0</a:depth><a:timeout>Second-180</a:timeout></a:activelock></a:lockdiscovery></a:prop>
 回复 引用 

#38楼 124.84.204.*  2008-04-18 15:09 瑞rui.star@126.com [未注册用户]
我模拟的HTTP RESPONSE,怎么把头上那个HTTP/1.1 200 OK 去掉呢,
都是自动给我加上的.
 回复 引用   

#39楼[楼主] 2008-04-18 15:49 jianyi      
@瑞rui.star@126.com
那个头应该可以控制的,你认真研究下HttpResponse类。
 回复 引用 查看   

#40楼 2008-04-21 08:23 云の世界      
thanks!解决了,context.Response.Status = "423 Locked";这样字就可以了。
 回复 引用 查看   

#41楼 221.237.67.*  2008-05-16 16:20 vancl[未注册用户]
谢谢提供,慢慢研究
 回复 引用   

#42楼 2008-11-02 10:21 EricWang      
强!!!

慢慢消化一下
 回复 引用 查看 

#43楼 2008-11-02 10:30 EricWang      
刚刚才发现,JIANYI的BLOG的背景图的啊。。。从上往下看或者从下往上看。。。看到一排箭头。。哈哈
 回复 引用 查看   

#44楼 221.223.227.*  2008-11-19 17:32 mj20030608[未注册用户]
有用JAVA实现的吗?小弟急求!我的QQ410202994,邮箱mj20030608@163.com
 回复 引用   

#45楼 2008-12-28 13:16 <夜风>      
正和我意,收藏了,谢谢!
 回复 引用 查看   

#46楼 113.249.34.*  2009-12-18 23:00 ___js[未注册用户]
请问楼主,我都是按照你的代码一模一样的实现,为何编辑打开的word文档总是只读,整了几天都不知道什么问题,请问有什么其他注意的地方吗?我的环境是vs2008+0ffice2007,是在vs的虚拟服务器上面,还没发布到IIS
 回复 引用   

#47楼[楼主] 2009-12-19 10:45 jianyi      
@___js
偶也不知道啊,哈哈,实际会碰到很多问题。
你可以先看看IIS的在线编辑word功能,然后用fiddler拦截下http 输出,对比下应该能发现原因。
 回复 引用 查看   

#48楼 2010-11-05 11:27 huanglang      

找这方面的内容已经好长时间了,博主的文章非常有帮助.
我按照博主说的步骤操作,现在打开没有一点问题.
但保存时出现问题如下:
1、保存时没有出错,但内容根本保存不了(比较奇怪的是,保存后打开,文字内容现实不了,但光标的最后位置变化了)。
2、保存到数据库的内容特别小,只有100多字节,通常一个word文件应该有10000多字节的呀!

请博主帮忙看看我的代码,不胜感激!
public void ModifyDocContent(int docId, byte[] data)
{
string sConnectionString = "server=csharpgroup;uid=sa;pwd=csharpgroup;database=TestWebDB";
SqlConnection conn = new SqlConnection(sConnectionString);
SqlCommand InsertCommand = new SqlCommand();
InsertCommand.Connection = conn;
InsertCommand.CommandText = "UPDATE [Document] SET size=" + data.Length + ",Content = @Content WHERE Documentid=" + docId;
InsertCommand.Parameters.Add("@Content", SqlDbType.Image, data.Length, "Content"); //注意,此处参数Size为写入的字节数
//读取文件内容,写入byte数组
InsertCommand.Parameters["@Content"].Value = data; //为参数赋值
try
{
conn.Open();
InsertCommand.ExecuteNonQuery();
}
catch
{
throw new Exception("出现壹!");
}
finally
{
conn.Close();
}
}
 回复 引用 查看 

#49楼 2010-11-05 11:29 huanglang      
急,在线等,请博主帮忙给以解决,多谢了.
 回复 引用 查看   

#50楼[楼主] 2010-11-05 11:37 jianyi      
@huanglang
很老的东西了,哈哈,看不出问题啊,多分析下。
 回复 引用 查看   

#51楼 2010-11-05 15:16 huanglang      
打开的时候,提示变成纯文本格式了.
是这个原因吗?
context.Response.ContentType = doc.ContentType;
这个应该是什么类型呢?我的写成了context.Response.ContentType = "application/msword"
是因为这个原因吗?

请博主指教。
 回复 引用 查看 

#52楼[楼主] 2010-11-05 15:24 jianyi      
@huanglang
测试一下不就知道了?
 回复 引用 查看   

#53楼 2010-11-05 15:30 huanglang      
我的为context.Response.ContentType = "application/msword" ,打开时格式变纯文本,什么文字都显示不了.
 回复 引用 查看   

#54楼 2010-11-05 15:31 huanglang      
哥哥,救命啊,都卡这里两天了.
 回复 引用 查看   

#55楼[楼主] 2010-11-05 15:35 jianyi      
@huanglang
在asp。net。里你下载word附件是怎么设的啊?
你自己Debug下,看上传的时候ContentType 是什么。
 回复 引用 查看   

#56楼 2010-11-05 15:40 huanglang      

下载就是用application/msword
上传还现在还是用文件的方式直接保存到数据库中,没有设置ContentType.
 回复 引用 查看   

#57楼 2010-11-05 15:43 huanglang      

自己实在是没辙了,不然也不会来麻烦博主的.
 回复 引用 查看   

#58楼[楼主] 2010-11-05 15:45 jianyi      
@huanglang
这篇文章写的时候还是用word03,你是用07了吧?你还是自己用fiddler trace下吧。 上传的时候就要把ContentType保存下来,然后用这个ContentType下载,不应该把ContentType写死的。
 回复 引用 查看   

#59楼 2010-11-05 15:51 huanglang      
我的是word03,现在只想实现这个功能,所以就把ContentType写死了.

要不我把我的代码发给您,麻烦您帮我看看,行吗?
 回复 引用 查看 

#60楼 2011-09-18 03:37 SkyPurple      
一直都无法真正实现Save, 无论如何修改, 打开Word后一直是只读状态,请教如何才能真正编辑Save到服务器
 回复 引用 查看   

#61楼[楼主] 2011-09-18 11:48 jianyi      
@SkyPurple
自己用Fidder debug下http输出,看看iis自带的和你的实现有什么区别吧

[转载]Office文档在线编辑的实现之二相关推荐

  1. Office文档在线编辑的实现

    因为项目的关系,研究了一下Office的在线编辑功能,写出来共享一下. Office xp之后的版本支持通过webdav协议(http的扩展)直接编辑服务器上的文件. IIS(6.0)支持webdav ...

  2. 用pageOffice控件实现 office 文档在线编辑Word 打开文档后在页面里触发事件

    OA办公中,业务需要编辑打开word文档后 执行一些js操作 怎么实现编辑打开word文档后 执行一些js操作呢? 2 实现方法 通过pageOffice实现简单的在线打开编辑word时, 通过设置 ...

  3. 通达OA-今日学习:OFFICE文档在线编辑控件与工作流表单手写签章控件的区别是什么?

    NTKOOFFICE文档在线编辑控件,控件提供商为重庆软航科技,使用范围:OA各个模块上传附件(比如文件柜.工作流.公告通知等模块),如果是Office文档,就可以在线编辑或阅读,在线编辑时可以加盖电 ...

  4. Office文档在线编辑

    Office文档特别是Word文档在线编辑基本上有如下几个方案: 1.使用dsoframer,毕竟是MS微软的东东,功能很强悍,而且国内的很多产品都是基于dsoframer开发的 2.使用WebOff ...

  5. JavaScript Office文档在线编辑备忘

    来源: http://www.cnblogs.com/jianyi0115/articles/677712.html http://www.cnblogs.com/fxwdl/archive/2009 ...

  6. 【Office文档在线编辑和预览服务搭建】

    友情提醒!文章篇幅巨长!!! 原博客文章https://blog.csdn.net/m0_66640832/article/details/124482483转移到此更新 搭建流程:域控服务==> ...

  7. Office文档在线编辑和预览服务搭建

    友情提醒!文章篇幅巨长!!! 搭建流程:域控服务==>OWA服务==>WOPI服务 1. 搭建域控服务器 准备一台服务器,干净环境,系统版本:window server 2016 服务搭建 ...

  8. 用pageOffice文档控件实现 office文档在线编辑

    第三方文档控件,pageOffice 系统开发中经常要处理办公文档,如果word,excel,ppt,编辑整理,保存,归档. 开发市场上也有很多第三文文档控件,多年的总结,还是认为pageOffice ...

  9. 文档在线编辑开发心得

    一.背景 在本次公司的开发任务中,偶然接触到了畅写office的文档在线编辑集成开发,在开发中遇到点问题,觉得这个东西挺有趣的,写此文章保存开发心得. 二.前期准备 文档在线编辑功能只有一个api.文 ...

最新文章

  1. php前端开发语言,web前端编程语言有哪些?
  2. 基于Xml 的IOC 容器-向容器注册
  3. 交际能力弱的人,适合当律师吗?
  4. [leetcode]36. Valid Sudoku c语言
  5. android判断正确密码,Android 监听EditText输入框 ,判断输入的密码是什么格式
  6. inode客户端连接成功上不了网_iNode智能客户端常见问题及解决办法
  7. 国考银保监会计算机类笔试,银保监会(计算机类)笔试资料(含2018-2019真题).zip...
  8. C#自学29—简体字繁体字转换
  9. ubuntu启动报错 hardware error cpu 0 machine check 0 Bank 6、ACPI BIOS Error (bug)Could not resolve symbol
  10. 极客时间学习笔记:03芯片分类
  11. 计算机键盘上的基准键是哪两个键,键盘上的基准键分别是什么?
  12. Java8里不得不说的那些常用日期处理,码起来~
  13. IE网页出现js错误修复方法_离水的鱼_新浪博客
  14. 怎样基于power supply class编写PSY driver
  15. 【CSDN竞赛第25期】赢热门图书《千脑智能》和定制周边
  16. G3,是塔克和阿德巴约的热火队
  17. 【Flutter】pubspec.yaml中的版本管理
  18. 电商平台-系统架构与技术选型
  19. 2022-2028全球与中国重型卡车轮胎市场现状及未来发展趋势
  20. 2018开门红,格力电器1月大涨28.01%,怒送1个涨停

热门文章

  1. 怎么批量修改html文件后缀,如何批量修改文件后缀名 超详细介绍
  2. 【面经专栏】独家整理【C++】面经
  3. 从阿里 Weex 一窥移动技术发展之路
  4. 网络攻击与防御技术期中习题
  5. php程序员 合川_PHP程序员将何去何从?
  6. RabbitMQ五种工作模式
  7. fcpx插件Stupid Raisins Sale Pop for Mac(37种促销标题模板)
  8. oa系统服务器价格,oa软件系统价格
  9. 二项分布的期望值 E(n)=np 推导
  10. 3DMax的中文版官方手册