使用Frontpage RPC管理web站点的文件
2005-11-29 21:43
302 查看
往往我们需要对一个web站点的文件进行管理,而常用两种方式:第一,通过ftp协议进行文件管理;第二,通过web页面提供的该功能(yahoo的公文包)。而这里将介绍第三种方式:FrontPage 服务器扩展(FrontPage Server Extensions Remote Procedure Call)。使用FrontPage 服务器扩展有以下优点:l 使创作者们能协作创建和维护web站点、直接在服务器计算机上编辑一个 Web 站点(节省下载时间),并且在不必编写程序的情况下,轻易地在站点上加入新功能。 l 支持站点计数器、全文搜索、电子邮件表单处理程序和其他由创作者使用 FrontPage 添加到站点的功能。您不必下载、购买或安装独立的CGI兼容的程序来实现上述功能。 l 能在许多流行的服务器平台,如 Windows NT 和 UNIX,以及许多流行的站点服务器,如 Microsoft Internet Information Services (IIS)、Apache、WebSite 和 Netscape 上工作。 l 在一个 Web 站点中移动、删除或重命名一个网页(只是网页的文件名,而不是必须传送到站点服务器的整个文件的名称)后,自动更新超链接。 l 支持与 Microsoft Office、Visual SourceSafe 和 Index Server 的集成。Frontpage RPC通过Frontpage RPC 方法来控制web站点,实现以上的功能。这里只是介绍如何通过Frontpage RPC对web站点的文件进行管理。对大家起一个抛砖引玉的作用。Frontpage RPC的是基于http协议的一种远程过程调用。Frontpage RPC通过http POST命令向web站点中特定的dll发送方法,而web服务器将返回带有操作结果信息HTML文档到客户端。客户端可通过该文档判断是否操作成功。Frontpage RPC方法位于“method=”后,方法名后面有一个冒号“:”,它是方法名与Frontpage 服务器扩展的版本号的分隔符。版本号后面跟着该方法的参数。每个参数以记号“&”作为第一个字母,参数名紧跟“&”后面。参数名与参数的值用“=”连接,中间不能由任何的空格符号。可以参见下面的例子:method=get document:server_extension_version
接下来看看在这里将会使用到的Frontpage RPC 方法,具体的参数可以参看(http://msdn.microsoft.com/library/en-us/spptsdk/html/SPPTWSSFPSERPC_SV01072918.asp?frame=true):l get document 获取指定的文档。l list documents 列出位于指定url的web站点下文件、文件夹和子站点以及他们的meta-info。l move document修改指定文件的文件名、移动指定的文件到指定的文件夹、复制指定文件。l put document 上传一个文件或文件夹到已存在的web站点。l remove documents 删除wen站点上指定的文件或文件夹。在编码的过程中应该注意一下几点:1. url编码问题:l 在http协议中发送的数据主体必须是8位编码的字符,也就是只能由0-225之间的字符组成。中文字符是不能出现的。所以在所有Frontpage RPC中方法中所有的参数都需要经过url编码。url编码方式是把字符相对应的二进制的值转换为十进制,然后再前面加“%”。url中文的编码方式先将中文编码成对应的字节,然后在在前面加上“%”。比如“中国”使用UTF-8的编码是“228”,“184”,“173”,“229”,“155”,“189”六个字节组成,那么url的对应得编码应该是“%228%184%173%229%155%189”。如果“中国”使用gb2312的编码是“214”,“208”,“185”,“250”四个字节,那么对应的url编码应该是“%214%208%185%250”l Frontpage RPC 中方法中所有的参数不能出现除数字和字母以外的字符,例如一般可以在地址栏看到的符号“.”、“_”都不允许出现在参数中。C#提供的UrlEncode方法不会对“.”、“_”这两个字符进行编码,所以我们需要写一个函数进行编码。l 文件的url中如果带有“;”、“=”、“[”、“]”都需要转义为“/;”、“/=”、“/[”、“/]”才进行url编码。否则会提示找不到该文件。2. html编码问题:html的编码与url相类似,只是html编码会将UTF-8“中国”编码为:“ä 184; 229; 155; 155; 189;”,gb2312编码为“Ö 208; 185; 250;”。3. 注意方法中的大小写。这个问题我是在写这篇文章的时候,做演示工程的时候发现的问题。因为实际使用中可能是版本的问题,大小写与sdk中的有些出入。例如oldUrl正确的是参数名应该是oldUrl,而微软官方文档中的是oldURL。4. Web站点和子站点的关系。曾经在开发的过程中,忽略的这个问题最后的直接后果是导致加班到晚上1点。在操作不同的子站点的时候,Frontpage RPC 方法发送的dll的url也是不一样的。而且子站点与子站点是独立的。不能够进行类似将子站点A的文件复制到子站点B这样的操作。最后还是看看一些关键的代码:
&service_name=/&document_name=service_relative_path/file_name
[&dir_name=directory_name][&effective_protocol_version=server_extension_version]
&old_theme_html=(true|false)&force=(true|false)[&doc_version=string]
&get_option=(none|0|1|2)&timeout=time_in_seconds[&validateWelcomeNames=(true|false)]
字体/代码 | 意义 | 例子 |
斜体 | 变量(参数)的值 | service_relative_path/file_name |
方括号([、]) | 可选的内容 | [&validateWelcomeNames=(true|false)] |
无格式文本 | 字面意义 | method |
分隔符(|) | 分开可选的选项 | (true|false) |
using System; using System.IO; using System.Net; using System.Web; using System.Text; using System.Collections; using System.Collections.Specialized; using System.Configuration; using System.Threading; using System.Net.Sockets; namespace FPSERPCClient { /// <summary> /// Summary description for FPSEPublish. /// </summary> public class FPSERPCClient { /// <summary> /// 构造函数 /// </summary> /// <param name="username">用于登陆站点的用户名</param> /// <param name="password">用于登陆站点的密码</param> public FPSERPCClient(string username, string password) { Credential = new NetworkCredential(username, password); } /// <summary> /// 删除web站点上指定的文件或文件夹。 /// </summary> /// <param name="uri">删除文件的url</param> /// <returns></returns> public string RemoveDocument(string uri) { Uri myUri = new Uri(uri, true); string webUrl, fileUrl; UrlToWebUrl(uri, out webUrl, out fileUrl); /// 这是最简单的一个方法 string postBody = String.Format(" method=remove documents&service_name={0}&url_list=[{1}]", UrlEncode(webUrl), UrlEncode(fileUrl)); return SendRequest(myUri.GetLeftPart(UriPartial.Authority) + webUrl.TrimEnd('/') + "/_vti_bin/_vti_aut/author.dll", postBody); } /// <summary> /// 发送Frontpage RPC方法的请求重载 /// </summary> /// <param name="uri">发送请求的目标Url</param> /// <param name="postBody">发送请求的主体</param> /// <returns></returns> private string SendRequest(string uri, string postBody) { return SendRequest(uri, postBody, null); } /// <summary> /// 发送Frontpage RPC方法的请求重载 /// </summary> /// <param name="uri">发送请求的目标Url</param> /// <param name="postBody">发送请求的主体</param> /// <param name="fileStream">下载文件保存的FileStream</param> /// <returns></returns> private string SendRequest(string uri, string postBody, Stream fileStream) { byte[] bPostBody = BodyEncoding.GetBytes(postBody); return SendRequest(uri, bPostBody, bPostBody.Length, fileStream); } /// <summary> /// 发送Frontpage RPC方法的请求重载 /// </summary> /// <param name="uri">发送请求的目标Url</param> /// <param name="postBody">发送请求的主体</param> /// <param name="postLength">发送请求的主体长度</param> /// <param name="fileStream">下载文件保存的FileStream</param> /// <returns>返回接受的Response,为html格式的字符串</returns> private string SendRequest(string uri, byte[] postBody, long postLength, Stream fileStream) { string strResponseText = null; Stream sendStream = null; HttpWebResponse response = null; Stream receiveStream = null; StreamReader responseTestReader = null; try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded; charset=utf-8"; request.Headers.Add("X-Vermeer-Content-Type", "application/x-www-form-urlencoded"); request.UserAgent = "DRSERPCClient"; request.Accept = "auth/sicily"; request.Expect = "200-ok"; request.KeepAlive = true; request.Credentials = this.Credential; request.Timeout = HTTPREQUEST_TIMEOUT; request.PreAuthenticate=true; // let's stop sending bunks of data prior to detecting 401 sendStream = request.GetRequestStream(); int iOffset = 0; while(postLength > 0) { if (postLength > 4096) { sendStream.Write(postBody, iOffset, 4096); postLength -= 4096; iOffset += 4096; } else { sendStream.Write(postBody, iOffset, Convert.ToInt32(postLength)); break; } } sendStream.Close(); response = (HttpWebResponse)request.GetResponse(); receiveStream = response.GetResponseStream(); int readBytes = 0; byte[] readBuffer = new byte[BUFFER_SIZE]; ///接受到的Response以“</HTML>/n”为分割符,后面的为下载文件的主体部分 while((readBytes = receiveStream.Read(readBuffer,0, readBuffer.Length)) != 0) { strResponseText += BodyEncoding.GetString(readBuffer, 0, readBytes); int separatorOffset = strResponseText.ToUpper().IndexOf("</HTML>") + 8; if(separatorOffset != 7) { strResponseText = strResponseText.Substring(0, separatorOffset); if(fileStream != null) { fileStream.Write(readBuffer, separatorOffset % BUFFER_SIZE , readBytes - separatorOffset); } break; } } ///把下载文件的内容写入文件流中,最后保存在磁盘上 if(fileStream != null) { while((readBytes = receiveStream.Read(readBuffer,0, readBuffer.Length)) != 0) { fileStream.Write(readBuffer, 0, readBytes); } } receiveStream.Close(); response.Close(); } catch (Exception e) { if(sendStream != null) sendStream.Close(); if(responseTestReader != null) responseTestReader.Close(); if(receiveStream != null) receiveStream.Close(); if(response != null) response.Close(); throw e; } return strResponseText; } /// <summary> /// 获取一个绝对Url的字站点地址,和相对该子站点的文件地址 /// </summary> /// <param name="uri">绝对URL</param> /// <param name="webUrl">子站点地址</param> /// <param name="fileUrl">相对子站点的文件地址</param> private void UrlToWebUrl(string uri, out string webUrl, out string fileUrl) { Uri myUri = new Uri(uri, true); string strUriPartial = string.Empty; for(int i = 0;i < myUri.Segments.Length; i++ ) strUriPartial += myUri.Segments[i]; string postBody = String.Format("method=url+to+web+url&url={0}&flags=0", UrlEncode(strUriPartial)); string response = SendRequest(myUri.GetLeftPart(UriPartial.Authority) + "/_vti_bin/shtml.dll/_vti_rpc",postBody); webUrl = GetReturnValue(response, "webUrl"); fileUrl = GetReturnValue(response, "fileUrl"); } /// <summary> /// 获取一个返回的html中特定的值 /// </summary> /// <param name="responseText">web站点返回的html字符串</param> /// <param name="key">需要获取值得key</param> /// <returns>返回该key的值 </returns> public string GetReturnValue(string responseText, string key) { int start = responseText.IndexOf(key + "="); if (-1 == start) return null; else start += key.Length + 1; int end = responseText.IndexOf("/n", start); return HtmlDecode(responseText.Substring(start, end - start)); } /// <summary> /// 获取一组返回的html中特定的值 /// </summary> /// <param name="responseText">web站点返回的html字符串</param> /// <param name="key">需要获取值得key</param> /// <returns>返回该key的值</returns> public string[] GetReturnValues(string responseText, string key) { int start = 0; int end = 0; string returnValue = string.Empty; ArrayList returnValuesList = new ArrayList(); while(true) { start = responseText.IndexOf(key + "=", end) + key.Length + 1; if(start == key.Length) break; end = responseText.IndexOf("/n", start); returnValue = responseText.Substring(start, end - start); returnValuesList.Add(HtmlDecode(returnValue)); } string[] returnValues = new string[returnValuesList.Count]; returnValuesList.CopyTo(returnValues); return returnValues; } /// <summary> /// url编码 /// </summary> /// <param name="url">需进行编码的URL</param> /// <param name="e">进行编码的类</param> /// <returns>返回编码以后的值</returns> public string UrlEncode(string url, Encoding e) { url = url.Replace(";", "//;"); url = url.Replace("=", "//="); url = url.Replace("[", "//["); url = url.Replace("]", "//]"); string encodedUrl = HttpUtility.UrlEncode(url, e); encodedUrl = encodedUrl.Replace(".", "%2e"); encodedUrl = encodedUrl.Replace("_", "%5f"); return encodedUrl; } /// <summary> /// url编码 /// </summary> /// <param name="url">需进行编码的URL</param> /// <returns>返回编码以后的值</returns> public string UrlEncode(string url) { return this.UrlEncode(url, UrlEncoding); } /// <summary> /// html编码 /// </summary> /// <param name="html">需进行编码的html</param> /// <param name="e">进行编码的类</param> /// <returns>返回编码以后的值</returns> public string HtmlDecode(string html, Encoding e) { string htmlDecoded = HttpUtility.HtmlDecode(html); byte[] htmlDecodedBytes = Encoding.Unicode.GetBytes(htmlDecoded); char[] htmlDecodedChars = Encoding.Unicode.GetChars(htmlDecodedBytes); htmlDecodedBytes = new byte[htmlDecodedChars.Length]; for(int i = 0; i < htmlDecodedChars.Length; i++) { htmlDecodedBytes[i] = (byte)htmlDecodedChars[i]; } htmlDecoded = e.GetString(htmlDecodedBytes); return htmlDecoded; } /// <summary> /// html编码 /// </summary> /// <param name="html">需进行编码的html</param> /// <returns>返回编码以后的值</returns> public string HtmlDecode(string html) { return this.HtmlDecode(html, HtmlEncoding); } } } |
相关文章推荐
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 \\ 节中包括 System.Web.SessionStateMod 或自定义会话状态模块
- Java使用POM一JAR包的形式管理JavaScript文件-WebJars
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 // 节中包括 System.Web.SessionStateMod 或自定义会话状态模块 -
- 微软ASP.NET站点部署指南(3):使用Web.Config文件的Transformations
- 微软ASP.NET站点部署指南(3):使用Web.Config文件的Transformations
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 // 节中包括 System.Web.SessionSta
- HDFS设计思路,HDFS使用,查看集群状态,HDFS,HDFS上传文件,HDFS下载文件,yarn web管理界面信息查看,运行一个mapreduce程序,mapreduce的demo
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 // 节中包括 System.Web.SessionStateMod 或自定义会话状态模块 -
- iis中web站点无法启动:另一程序正在使用该文件,进程无法访问--解决
- 有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 <configuration>\<system.web>\<
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 <configuration>\<system.web>\
- 只有在配置文件中或 Page 说明会 enableSessionState 至 true 时刻,能够使用会话状态。另外,还要确保应用程序配置 // 段包含 System.Web.SessionSta
- 在Web.Config文件中使用configSource,避免动态修改web.config导致asp.net重启(另添加一个Config文件用于管理用户数据)
- 在Web.Config文件中使用configSource,避免动态修改web.config导致asp.net重启(另添加一个Config文件用于管理用户数据)
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 // 节中包括 System.Web.SessionSta
- HDFS设计思路,HDFS使用,查看集群状态,HDFS,HDFS上传文件,HDFS下载文件,yarn web管理界面信息查看,运行一个mapreduce程序,mapreduce的demo
- 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 <configuration>\<system.web>\<httpModules> 节中包括..
- Web文件管理系统!免费使用版
- 一个简单的管理Web站点文件的页面程序(修改版)
- 转--只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 // 节中包括 System.Web.SessionStateMod 或自定义会话状态模块