2009年4月21日星期二

原来是目录权限的问题

在Sharepoint中,使用Generic Handler来读取Image并显示出来,使用的是transmitfile函数。当发布在Sharepoint中,出现403 FORBIDDEN错误。图像所在路径是一个共享目录,如\\ibadev\8080\images这样的目录。

经查明,问题在于,共享目录是否填加了“Everyone”权限。我发现images这个目录,只有qfang有访问权限,所以才会现只有qfang登录sharepoint时,才会显示图像的情况。后来,给images目录添加了everyone可访问的权限,一切就都正常了。

2009年4月9日星期四

SharePoint Theme

SharePoint Theme

Represents a collection of graphics and cascading style sheets that can modify how a Web site looks.

Real World Example

A business group wants to create a common high-level graphical look and feel for a set of Web sites. They hire a graphics designer to create a new theme that can be installed on Windows SharePoint Services 3.0 or Microsoft Office SharePoint Server 2007, and then applied to any Web site to provide the intended graphical scheme.

Technical Details

Themes in SharePoint Products and Technologies are installed on the front-end Web server file system and can be referenced by any Web site in the SharePoint environment. If a Web site refers to a theme that is not available, it should render as if no theme was applied.Support DetailsAfter a theme is installed, execute an IISReset command to make the theme available.


Themes re-skin the layout by changing colours and images used in the design. Since a theme is just a CSS file and images, the layout of the page such as the location of the navigation is controled by the master page.
To create a new theme, copy an existing theme from the C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\THEMES directory into a new directory.
Edit the C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033\SPTHEMES.XML file and add a section for your new theme:

<Templates>
<TemplateID>NewDirectoryName</TemplateID>
<DisplayName>Theme Display Name</DisplayName>
<Description>Give Description of the theme</Description>
<Thumbnail>images/customimage.png</Thumbnail>
<Preview>images/pagepreview.gif</Preview>
</Templates>
Perform an IIS Reset and then select the new theme from the Site Settings page.

使用IHttpHandler下载文件

namespace IBA.ECommerce.WebParts.UserControls
{
// <system.web>
// <httpHandlers>
// <add verb="GET,POST" path="GetImage.ashx" type="IBA.ECommerce.WebParts.UserControls.GetImageHandler"/>
// </httpHandlers>

public class GetImageHandler : IHttpHandler
{
#region IHttpHandler Members

public bool IsReusable
{
get { return false; }
}

public void ProcessRequest(HttpContext context)
{
Guid dociId = new Guid(context.Request["docid"]);
Document doc = Document.Get<Document>(dociId);
if (doc != null)
{
context.Response.ClearHeaders();

FileInfo fileInfo = new FileInfo(doc.FullPath);

context.Response.AddHeader("Content-Disposition", "attachment; filename=" + doc.Path2);
context.Response.TransmitFile(doc.FullPath);

context.Response.End();
}
}

#endregion
}
}

2009年4月8日星期三

如何为一个系统提供技术解决方案

Supply Portal是IBA的一个新项目。这个项目也是和SAP相关,需要用MOSS实现和客户的交流,与Ecommerce相似。不过,与Ecommerce不同的是,它需要很多工作流。

现的情况是,有一个工程师在Belgium作需求分析,它了解了整个的工作流程。需要我们MOSS工程时提技术解决方案。

使用SmartPart时的UserControls目录的权限

这个目录需要设置为Everyone可访问才行。

2009年3月24日星期二

在SharePoint的Webpart中无法使用Resources

原因未明

使用ObjectDataSource重新查询

在使用ObjectDataSource作为数据源时,如果需要重新查询,则使用ObjectDataSource的Select方法即可。如下列代码:

protected void btnSearch_Click(object sender, EventArgs e)
{
this.CatalogDataSource.Select();
this.listCatalog.DataBind();
}

NHibernate在web.config中的配置

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<!-- SQL dialect -->
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<!--<property name="connection.connection_string1">Server=124.254.10.29,1436\sql2008;Initial Catalog=novi;User Id=novi;Password=L7JBwNq</property>-->
<property name="connection.connection_string">Server=devdc01;Initial Catalog=IBA_ECommerce_DB;User Id=ecomm;Password=iba+1234</property>
<!-- others -->
<property name="show_sql">true</property>
<!-- mapping files -->
<mapping assembly="IBA.ECommerce"/> 这个很重要,是所有映射类所在的DLL。
</session-factory>
</hibernate-configuration>

ListView中取得更改行的数据

在ListView中Update数据时,要取得所更新的数据信息。最好的方法是设置ListView的DataKeyNames。DataKeyNames即为绑定的数据对像的属性。比如这个Material的ID即为其Identify Field。那么,我们就可以在更新ListView时,取得所更新的DataKeyValue。

方法如下:

1. 设置ListView的DataKeyNames属性
<asp:ListView ID="listCatalog" runat="server" DataKeyNames="ID"
DataSourceID="CatalogDataSource" onitemupdated="listCatalog_ItemUpdated">
<LayoutTemplate>

2. 在ListView的OnItemUpdated事件中,
protected void listCatalog_ItemUpdated(object sender, ListViewUpdatedEventArgs e)
{
int i = listCatalog.EditIndex;
string reference = listCatalog.DataKeys[i].Value.ToString();
ShowMessagePanel(reference);
}


取得了修改行的ID值后,就可以使用Model的如Find或GetByID等得到修改的Class,进而修改数据。

ObjectDataSource和ListView的Update顺序

ListView的DataSourceID = CatalogDataSource

下而在更新时,事件的执行顺序:

protected void CatalogDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
// 1
}

protected void listCatalog_ItemUpdated(object sender, ListViewUpdatedEventArgs e)
{
// 2
}

2009年3月18日星期三

使用ListView + ObjectDataSource更新数据

这里面最关键的问题在于,当Update时,如何获取到修改行的TextBox的值。经探索,方法如下:
  1. 为ObjectDataSource指定UpdateMethod,并且设置UpdateParameters
  2. UpdateParameters只需要使用<Parameter即可
  3. 为ObjectDataSource创建OnUpdating事件
OnUpdating要做的工作如下:
protected void ObjectDataSource1_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
object o = ListView1.Items[ListView1.EditIndex].FindControl("txtQty");
if (o.GetType() == typeof(TextBox))
{
e.InputParameters[0] = ((TextBox)o).Text;
}

}
下面是ListView中的EditItemTemplate内容:
<EditItemTemplate>
<tr>
<td>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</td>
<td>
<asp:TextBox ID="txtQty" runat="server"></asp:TextBox>
</td>
<td>
<asp:LinkButton ID="LinkButton1" CommandName="Update" runat="server">Update</asp:LinkButton>
<asp:LinkButton CommandName="Cancel" ID="LinkButton2" runat="server">Cancel</asp:LinkButton>
</td>
</tr>
</EditItemTemplate>

ListView的使用Sample

<h3>ListView Templates Example</h3>
<asp:ListView ID="ContactsListView"
DataSourceID="ContactsDataSource"
DataKeyNames="ContactID"
runat="server">
<LayoutTemplate>
<table cellpadding="2" width="640px" border="1" runat="server" id="tblProducts">
<tr runat="server">
<th runat="server">Action</th>
<th runat="server">First Name</th>
<th runat="server">Last Name</th>
</tr>
<tr runat="server" id="itemPlaceholder" />
</table>
<asp:DataPager runat="server" ID="ContactsDataPager" PageSize="12">
<Fields>
<asp:NextPreviousPagerField ShowFirstPageButton="true" ShowLastPageButton="true"
FirstPageText="|<< " LastPageText=" >>|"
NextPageText=" > " PreviousPageText=" < " />
</Fields>
</asp:DataPager>
</LayoutTemplate>
<ItemTemplate>
<tr runat="server">
<td>
<asp:LinkButton ID="EditButton" runat="Server" Text="Edit" CommandName="Edit" />
</td>
<td>
<asp:Label ID="FirstNameLabel" runat="Server" Text='<%#Eval("FirstName") %>' />
</td>
<td valign="top">
<asp:Label ID="LastNameLabel" runat="Server" Text='<%#Eval("LastName") %>' />
</td>
</tr>
</ItemTemplate>
<EditItemTemplate>
<tr style="background-color: #ADD8E6">
<td>
<asp:LinkButton ID="UpdateButton" runat="server" CommandName="Update" Text="Update" />
<asp:LinkButton ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" />
</td>
<td>
<asp:TextBox ID="FirstNameTextBox" runat="server" Text='<%#Bind("FirstName") %>'
MaxLength="50" /><br />
</td>
<td>
<asp:TextBox ID="LastNameTextBox" runat="server" Text='<%#Bind("LastName") %>'
MaxLength="50" /><br />
</td>
</tr>
</EditItemTemplate>
</asp:ListView>

2009年3月17日星期二

Refactor IBA Ecommerce Application

原先设想的是在MOSS端,只从Cache DB中取得数据,但经过最近的分析后,还需要通过Web Service从SAP端获得数据。而原来的Architecture并没有考虑到这个问题,因些需要对Architecture 进行Refactor。

使用SmartPart将UserControl引入SharePoint

SmartPart是一个SharePoint的Feature, 它可以使我们开发的Web UserControl直接在SharePoint 2007中的Web page中,以Web Part的形式显示,真是天才一样的作品,我认为都应该作为SharePoint的核心功能,否则开发SharePoint的Web Part实在是一件非常头痛的事情。

首先下载SmartPart安装包,然后上传至服务器,运行Setup.exe。在运行过程中可以选择要开启这个feature的站点。成功安装后,去相应的站点的Site Collection Feature中,把return of smartpart的feature active,就可以使用了。

首先,我们用VS2008创建一个Web usercontrol,它一共包含三个文件:
  • WebUserControl1.ascx
  • WebUserControl1.ascx.cs
  • WebUserControl1.ascx.designer
其中,一定要在WebUserControl1.ascx中做两处修改:
  1. 将<%@ Assembly Name="ReturnOfSmartPart, Version=1.3.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" %>加入顶部,引用assembly。
  2. 修改<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs",将CodeBehind换成CodeFile
  3. 在类声明(public partial class WebUserControl1 : System.Web.UI.UserControl)前面加入:System.ComponentModel.Description("WebUserControl1")]。这样可以使SmartPart寻找的UserControl列表中显示自定义的User Control名称。
做了这两个修改后,在SharePoint的站点下,如VirtualDirectory/8080/下面,创建一个UserControls目录,这点非常重要,名字绝对不能有差。接着将上面的三个文件,直接放入这个文件夹内就可以了。

使用方法:
  1. 进入SharePoint的相应站点,Edit Page -> Add Webpart -> Add SmartPart Webpart
  2. Modify Shared Web Part
  3. 选择WebUserControl1对应的Webpart即可。

2009年3月9日星期一

[转]CHAR, VARCHAR, TEXT, NCHAR的不同

  1. CHAR。CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充。
  2. VARCHAR。存储变长数据,但存储效率没有CHAR高。如果一个字段可能的值是不固定长度的,我们只知道它不可能超过10个字符,把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。为什么“+1”呢?这一个字节用于保存实际使用了多大的长度。从空间上考虑,用varchar合适;从效率上考虑,用char合适,关键是根据实际情况找到权衡点。
  3. TEXT。text存储可变长度的非Unicode数据,最大长度为2^31-1(2,147,483,647)个字符。
  4. NCHAR、NVARCHAR、NTEXT。这三种从名字上看比前面三种多了个“N”。它表示存储的是Unicode数据类型的字符。我们知道字符中,英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。nchar、nvarchar的长度是在1到4000之间。和char、varchar比较起来,nchar、nvarchar则最多存储4000个字符,不论是英文还是汉字;而char、varchar最多能存储8000个英文,4000个汉字。可以看出使用nchar、nvarchar数据类型时不用担心输入的字符是英文还是汉字,较为方便,但在存储英文时数量上有些损失。
根据以上几个datatype的不同,由于Unicode编码比非Unicode编码要多很多字节,因此,不存在多语言的情况下,就尽量避免使用n开头的类型。

2009年3月5日星期四

使用SharePoint Designer 2007为Page创建DataView

应用场景:
某E-commerce系统需要一个显示零件信息的详细页面。在这个详细页面上,需要显示此零件的一些零件图。
页面预览:


技术实现:

左侧的Part基本信息是采用Custom Web Part来实现的,右侧的图像是使用Office SharePoint Designer 2007来实现的。具体的实现方法是:
  1. 创建一个用于显示Part Detial的PartDetial.aspx在Web Part Page (Docuemnt) library中。
  2. 创建一个Part Picture Library用于存放上传的Part Pictures.
  3. 为Part Picture Library创建一个新Column - PartID (Single Textbox)用于存放Part ID。此即为零件的唯一标识。
  4. 使用SharePoint Designer 打开sharepoint 站点,编辑PartDetail.aspx页面
  5. 在适当的位置(Web Part Zone)添加一个DataView
  6. 选择DataSource为Part Picture library
  7. 在Design页面中单击DataView旁边的小三角号,可显示操作菜单。
  8. 选择默认的Layout, 编辑Columns,加入合适的字段。对于Picture Library, 添加"URL Path"后会自动在页面上输出图像。
  9. 进入Filter管理器,新增加一个Filter为Part ID。并设置其根据QueryString来取得值。
  10. 保存页面(Check In)即可

2009年2月28日星期六

使用7z备份站点文件

使用下列命令可以将源目录(文件)压缩为gzip格式。我是用于备份数据库而使用gzip格式的,因为这种格式体积较小,可以通过phpMyAdmin来进行数据库还原。

./7z -a -tgzip $target_name.gz $source_site

使用WPS导出MySQL数据库

下面是正确的脚本用来导入Mysql数据库,并证明可以通过phpMyAdmin导入。

./mysqldump -c -e -uroot --default-character-set=gbk --skip-set-charset --hex-blob rzchina > rzchina_db.sql

get-content rzchina_db.sql | set-content -encoding utf8 rzchina_db_final.sql

Windows PowerShell Pipelines

PowerShell 中的管道操作符—— 大于号(output) 是可以使用的,但input操作符—— 小于号 ,是不在wps 1.0 版本中支持的,这确实很让人失望。 我本想使用mysql database_name sql_script_file_name的命令来进行数据库restore,但看来是无法执行了。

不过,我发现了两个很有用的command :
  • get-content
  • set-content
使用mysqldump导出时,在windows下创建的文件是unicode,而不是utf-8的,这样在导出utf-8数据库时,脚本中会出现乱码。因此可以采用下面的命令将txt文件转换为utf-8格式的:
get-content rzchina.sql | set-content -encoding utf8 rzchina_utf8.sql

2009年2月26日星期四

MOSS 2007的Query Filter WP出现问题

当在IBA Ecommerce Application的MOSS站点的web page中填加QueryString Filter Web Part时,出现an error occurs这样的错误,然后就无法添加了。

我原以为是因为我自定义web part的问题,但我在没有custom web part的页面中,也是无法添加。因此我怀疑是share point出了问题。由于这个web part是MOSS具有的feature, WSS没有,因此只好在另一台机器上重新安装一下,看看到底是什么原因。

2009年2月5日星期四

在TFS上创建开发者博客

TFS全称Team Foundation Server,是微软面向软件开发的大一统的解决方案,包括项目管理及代码管理等全套功能。在开发中,通过日志来发布每天或几天的工作进展,是一个很好的任务汇报、追踪和交流的方式。那么如何在TFS中创建开发者博客呢?

TFS Portal是TFS的网站入口,它是一个Share Point的站点。在给开发者权限后,每个开发者可以创建一个属于自己的博客,方法如下:
  1. 登录进TFS Portal。如果不知道地址,可在VS2008中,在Team Exploere的站点名称上点右键,可以找到“Show Project Portal”,单击后即跳转至网站首页。
  2. 在“Site Actions”中选择“Site Settings”,然后创建一个新Site。
  3. 选择“Blog”模板。
  4. 完成!更改一下站点标题,如“Blade's Development Blog”,再在Themes中选个主题,就可以发布日志了。
发布日志时需要注意,请使用IE浏览器,Chrome和Firefox编辑时,都不能使用Rich Editor。Enjoy!

VS2008和显卡的小Bug

发现一个VS2008的小Bug, 在我使用的DELL Server上,可能由于显卡不够强劲,经常会出现界面上一些部分消失(重画失败)的情况。后来发现现将Options中的动画效果关闭,再重启VS2008,就不重现问题了。另外,Google的Desktop也会影响VS2008。

购物车的局部OOD

现要实现一个基本的购物车功能。客户将选中的零件填加至(H)购物车,然后生成订单。在这个需求中,创建了下面几个类:
  • Order
  • OrderItem
  • Basket
  • BasketItem
  • Part: 零件类
我的设计是让BasketItem继承自Part, 而OrderItem再继承自BasketItem。但现在出现个小问题,就是当将Basket生成订单时,要将BasketItem转成OrderItem,而这样对象转换是不支持的。因此需要重新设计一下。

我想来想去,觉得还是用下列的办法:
在Order中创建一个BasketItems属性,专门用于存放Basket中的Items,只在订单生成时用到。而平时在显示Order数据时,使用的是OrderItems。

父类的对象和子类的对象的转换

今天遇到一个关于OO的非常基础、非常easy的小问题,确怎么样没想明白。记录如下:

Class A是Class B的父类: class B extends A。现在:
A a  = new A();
B b = new B();
如果:
b = (B)a
则是错误的;
而:
a = (A)b
就是正确的。

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特性可以加快我们开发时的部署。便于程序引用更新。