2009年1月26日星期一

第一个PowerShell脚本:备份Drupal站点

今天完成了第一个Windows PowerShell脚本,比较开心。这个脚本的功能是:
  • 备份Drupal sites目录并压缩
  • 备份Drupal数据库并压缩
在运行脚本之前,要创建一个用于存放备份文件的目录,如SiteBackup,然后分别创建DB和Site目录分别用于存放数据库的Drupal程序文件。
脚本source code如下:

# Usage:
# backup_drupal_db.ps1

Write-Host "This script will backup&zip the drupal database and zip it."

$site_name = "rzchina"
$db_name = "rzchina"
$drupal_site_dir = "C:\XAMPP\xampplite\htdocs\rzchina\sites"

$target_db_dir = "C:\Users\example.net\Site-Backup\DB"
$target_drupal_dir = "C:\Users\example.net\Site-Backup\Site"

$mysql_bin_dir = "C:\XAMPP\xampplite\mysql\bin"
$7zip_bin_dir = "C:\Program Files\7-Zip"

$curr_dir = Get-Location
$curr_date = date -format "yyyyMMdd-Hmss"

# Backup database
$target_db_filename = $target_db_dir + "\" + $db_name.ToString() + "_" +

$curr_date.ToString()


$sql_filename = $target_db_filename + ".sql"

Write-Host "Start backup db..."

cd $mysql_bin_dir

./mysqldump -uroot -c -e --default-character-set=gbk --skip-set-charset --hex-blob $db_name > tmp_sql
get-content tmp_sql | set-content -encoding utf8 $sql_filename

Write-Host "DB backup ended."

# Zip db file
Write-Host "Start zipping...";

cd $7zip_bin_dir

$zip_filename = $target_db_filename + ".7z"

./7z.exe a $zip_filename $sql_filename

# Clean up
Write-Host "Clean up..."
del $sql_filename;

# Zip Drupal Site File
$zip_site_filename = $target_drupal_dir + "\" + $site_name + $curr_date.ToString() + ".7z";
./7z.exe a $zip_site_filename $drupal_site_dir

Write-Host "The End."

cd $curr_dir
由于是第一个脚本,因此略显幼稚,不过任务还完成的不错。接下来研究如何传递参数,实现更通用的脚本。

决定使用Windows Powershell

Windows Powershell是一个比较强大的脚本引擎,关于它的历史和来源我都不是很清楚,但其实这些并不重要,重要的是它能做什么以及是否好用。Windows Powershell可以使我们在控制台中轻松的通过各种丰富的命令操作文件等系统资源。

我现在有一个很简单的需求:备份网站程序。这个网站程序是由PHP和MySQL构成的,使用的是Drupal框架。我需要定期将Drupal目录下程序文件和数据库进行备份,而且我的开发环境是Window s Vista和XAMPP。因此我决定使用Windows Powershell来创建一个脚本,我只需要定期的执行这个脚本,就可以轻松的对网站实现备份。

Windows Powershell下即可以使用linux命令,也可以使用dos命令。当然,我还没有考证到底有多少的linux命令可以被支持,像clear和ls这样的简单命令是支持的。Windows Powershell的脚本文件扩展名是“.ps1”。请注意,后面是阿拉伯数字1,而不是字母l。它的全称应该指power shell 1,即版本号。

在默认的安装状态下,Windows Powersehll是不能直接运行ps1脚本的。这主要是从安全方面考虑。我从下面这个网址获得了一些信息:
这篇文章也是转译的,msdn原文在:
这篇文章主要讲解如何创建WPS脚本,安全策略和一些有用的小技巧。

简单的讲,使用
Get-ExecutionPolicy
命令可以获得当前WPS的安全策略设置。我现在的是:Restricted。这表明任何脚本(包括你自己写的)都是不能运行的。一共有以下几种可以设置:
  • Restricted
  • AllSigned
  • RemoteSigned
  • Unrestricted
这个是按照等级逐渐宽松的顺序排的。一般设置为RemoteSigned即可,这样即可以运行我们自己写的脚本,又可以对网上下载的脚本进行运行限制。使用
Set-ExecutionPolicy RemoteSigned
即可以更改脚本安全策略。Vista用户要注意,需使用管理员身份运行Powershell.exe才能更改。

2009年1月19日星期一

让SharePoint的WebPart连接外部数据库

关键字:MOSS 2007, WebPart, 数据库
摘要:本文主要介绍如何使WebPart能读取外部数据库的数据。

应用场景

正如MSDN所说的那样,WebPart是一个很好的扩展SharePoint功能的机制。它可以被安放于任何一个Web Part Page页。现在很少有应用是离开数据库的,因此使用WebPart连接外部数据库也是一个很常用的技巧。

MOSS 2007中引用了BDC机制,可以通过配置使SharePoint与外部数据进行交互,如SAP和CRM等。但是,只使用BDC是不能完成所有的需求的,比如购物车这样的功能。

现在有这样一个应用场景:某生成零件的公司使用SharePoint来开发一个网上零件订购系统。客户可以通过网上浏览所有可选的零部件,然后有选择的购买。这就是很普通的购物车的功能。这个公司同时还使用SAP作为企业的ERP,因此零部件和订购信息等部分来自SAP。但是,在本系统的设计中,我们创建了一个单独的数据库作为SAP数据的中转站,而不是全部与SAP进行直接的交互。这样做的好处在于:一方面可以使用这个数据库作一个缓存(因为直接与SAP通过Web Service进行交互,肯定效率上有所降低);另外也更安全(可以有选择的将数据导入中间数据库)。

设计分析

本项目中使用Web Part作一些关键业务逻辑的开发:比如购物车(My basket)的功能。My basket用于存放当前用户选购的零部件,当用户确认购买后就生成订单。那么我们使用Web Part来实现购物车的界面。零件的显示直接使用BDC List,然后在其Action中加入一个新的跳转地址,如:http://demosite:1010/MyBasket/PartID=xxxxxx。整个购物站点是一个Site Collection,而MyBasket是一个Site。然后在MyBaset的首页上填加一个MyBasket的WebPart即可。

那么这个MyBasket就是关键的功能模块了。

MyBasket需要连接B机的SQL Server 2005数据库,获取购物车数据。我使用一个单独的Class Library作为Model类和数据库类,它会生成一个DLL文件,只需将它放置在bin目录中即可。购物车的结构如下图所示。


更改代码访问权限

但当我将MyBasket这个web part发布至SharePoint站点时,出现了下方的错误信息:
请求 System.Data.SqlClient.SqlClientPermission, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 类型的权限已失败。
解决办法是:
最简便的方法是:更改web.config中的Trust Level至WSS_Medium。代码如下:
<trust level="WSS_Medium" originurl=""></trust>
<trust>是IIS的配置文件的一个标签,用于指定代码访问安全级别,详细内容可参考下面的网址:http://doc.51windows.net/iismmc/?url=/iismmc/htm/aacontrustelement.htm。

还有另外一种方法:因为web.config默认的trust level是Minimal(最小),它载入的是一个web_minimaltrust.config配置文件。 我们只需要将SqlClientPermission加入最小权限中就可以了,下面是具体的操作,不过我不推荐这种方法

首先在C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\CONFIG中找到wss_mediumtrust.config文件,找到其中的两部分代码:
<securityclass name="SqlClientPermission" description="System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> </securityclass>
<securityclass name="SqlClientPermission" description="System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
</securityclass>
将这两部分分别放置在wss_minimaltrust.config文件的对应位置,重启IIS后MyBaset WebPart就可以连接外部数据库了。

2009年1月18日星期日

如何使用VS2008做SharePoint 2007的Web Part开发

关键字:WSS3.0, WebPart
摘要:本文主要介绍如何使用VS2008做WSS3.0下的WebPart部署。

有一个项目是采用MOSS 2007做框架进行开发,感觉MOSS确实很强大,不过也有很多麻烦之处。最近专注于使用Web Part作功能扩展,其间也遇到了一些问题,来这里和大家分享一下。

VS2008有一个SharePoint extension for VS2008提供了开发Web Part, Feature, 和Site Defination等的模板,但有一个缺点是它必须安装在Windows 2003和WSS 3.0上,可通常我们做开发都是使用的Windows XP或Vista,这就造成了不小的麻烦。MSDN中推荐使用虚拟机来做开发,这的确是个很消耗资源但比较有效的方法。目前我就是使用这种方法。

另外,SharePoint extension for VS2008可以直接部署到本地的SharePoint的80站点中。要想Deploy到其它站点上,我还没有找到方法。它在布置时会生成一个setup.bat文件,但如果不在本地机部署的话,就不能生成这个文件。

即然如此,只好找最原始的部署Web Part的方法了。MSDN上有一篇"Deploying Web Parts in Windows SharePoint Services"我根据我的理解整理了一下,下面是具体的方法。

我使用的机器名为A,其上有一个虚拟机B,A使用的是Vista系统,B使用的是Win2003。
  1. 在A上使用VS2008开发好Web Part后,编译生成WebPart的DLL文件WebPartProject1.dll。
  2. 将这个dll文件放置在站点的bin目录中,或GAC(C:\Windows\assembly)中均可。如果这个Web part只适用于某个Site的话,放在其bin(%SYSTEMDRIVE%\inetpub\wwwroot\wss\VirtualDirectories\\bin)目录中较为合适。SharePoint 2007中,每个Application下有一个_app_bin目录,大家一定要注意:不要将此目录当成bin目录。如果没有bin目录,则需要手动创建一个。这个目录是SharePoint预留的。我将dll放在了bin中。
  3. 我把B上的Web Application的目录设置了共享,并在开发机A上Map了一个驱动器给它。这样可以在Build Web Part project时,直接使用Build-Events中的DOS命令将DLL直接发布至bin目录中。
  4. 接下来,如果按照MSDN那篇文章的作法,应该是创建一个WebPart1.webpart文件,然后按下图所示的格式写XML。下图的代码是直接从msdn上copy过来的,需要更metadata部分和title以及Description部分的内容。
然后将这个WebPart1.webpart文件上传至要发布的站点的WebPart的Catalog目录中。结果是:失败!

上传是可以成功的,但当预览WebPart时,就会出现错误,问题出在CreateChildControls。然后在页面上添加这个Web part也会出现“assembly or codebase is invaild”类的错误。而且我的Web part代码异常简单,只是输出了“hello world”。因此可以断定问题是由于SharePoint没有找到DLL文件。

和dll文件配置有关的有两个地方,一个是web.config,一个是WebPart1.webpart。我又查看了Walkthrough: Creating a Basic Web Part 这个文档,发现可以不创建.webpart文件,而直接通过Web Part Gallery中的“New”来创建新的Web Part。这个功能会列出所有可用的Webpart的dll(列在web.config的SafeControl中的),然后选择其中的进行填加。通过这个功能我看到了我的WebPart1,然后选择了添加。这次可以成功预览了。

我对比了一下通过SharePoint导出的.webpart的XML文件,发现MSDN示例给的XML和这个有出入。在SharePoint导出的.webpart文件中,是这样设置type的:


我的理解是:首先是带namespace的class name,然后是class name。不知道正确与否。

在发布成功后,肯定需要调试。Web part以DLL发布的,因此要重新加载,必须重启IIS。这点也造成了不小的麻烦。

希望本文对朋友们开发MOSS 2007的Web Part有帮助。

2009年1月16日星期五

.NET Application Settings for Class Library


在.NET开发中,我们经常会在Project Settings中创建一些字符串,用于存储application/user scope的变量。现在有这样一个应用场景:
  • project A 是 Data Access Layer, 生成A.dll
  • project B 是 Web Project,调用A.dll进行数据库操作。
  • A.dll中,从Project的Settings中创建的DBConn字符串中获取DB Connection String.
这时,问题出现了:当运行project B时,当进行数据库连接时,所要读取的是project A的project settings中的DBConn呢,还是project B中的DBConn?

其实这个问题应该追踪其本源,那就是Project Settings中的字符串都存放在何处了。

在msdn上:http://msdn.microsoft.com/en-us/library/a65txexh(VS.80).aspx 有关于 Application Settings的介绍,解释的比较全面。我简单总结一下:
  1. Application Settings用于存放两种变量:全局的和用户的。全局的变量是用户无权更改的;而用户变量可以在程序运行时进行更改及储存。
  2. 所有的变量和值存放于app.config这样一个xml文件中。具体位置应该就在Application所在目录。
但现在有问题了,假如我的是一个Class Library,那这个app.config存放于哪里?如果其它application引用了这个DLL,读取的是其它application所对应的app.config还是引用的DLL自带的app.config呢?

还是在http://msdn.microsoft.com/en-us/library/a65txexh(VS.80).aspx这篇文章中,我找到了一段注释,大概的意思就是:除了Visual Studio Tools for Office DLL project,其它的Class Library Project不配有application settings. 有点迷惑了。

TBC

Visual Studio 2008 Project Properties Post-Build Events

关键字:VS2008, 部署
摘要:本文主要介绍如何使用工程属性中的Build Events。

Post-Build Events在项目的属性页面中,可以用来在项目Build成功后执行DOS命令,可以用来将生成好的dll文件等copy至指定的目录。我在开发SharePoint的Web Part时使用到了这个特性。Web Part Project引用了Model Project,这样,将Model的Project的Build-event设置为将生成的model.dll copy至web part project的bin目录中。

VS2008提供了一些预定义的变量,可以通过其Event Edit编辑框来查看,比如$(TargetFileName)就表示此project生成的dll文件。

这里需要注意的是:如果要在Post-Build Event中填入路径地址的话,需要加双引号,如:
copy $(TargetFileName) "C:\Documents and Settings\qfang\My Documents\IBA-Projects\IBA_Ecommerce_Demo\IBA-Ecommerce-Demo\Bin"
如不加双引号,那么像Documents and Settings这样的地址就会出错。

还有一点,比如上面提到的情况,一个网站正在使用中,然后需要将另外的DLL放置在网站的bin目录中时,需要首先将IIS关闭(使用iisreset /stop命令也可),然后才能copy成功。因为当网站在使用中时,bin目录里的dll文件处于被加载状态,无法覆盖。而一旦copy失败,则整个项目也就返回编译失败的信息。

灵活运用Build-event特性可以加快我们开发时的部署。便于程序引用更新。