分享
 
 
 

使用Frontpage RPC管理web站点的文件

王朝c#·作者佚名  2006-12-17
窄屏简体版  字體: |||超大  

使用Frontpage RPC管理web站点的文件

使用Frontpage RPC管理web站点的文件 往往我们需要对一个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

&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)

接下来看看在这里将会使用到的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这样的操作。

最后还是看看一些关键的代码:

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);

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有