SharePoint Online -用SharePoint Online进行基于云的协作

[原文发表地址] SharePoint Online – Cloud-Based Collaboration with SharePoint Online

随着Office 365的发行,微软将提供下一代微软在线服务一项基于SharePoint 2010, Exchange 2010 Lync Server 2010,并基于云的协作和通信服务。Office 365目前正处于测试阶段。在微软管理的云数据中心中,它会提供基于订阅的SharePoint, ExchangeLync的软件软件即服务(Saas)。

SharePoint Online作为SharePoint 2010的云版本,将为用户提供许多与SharePoint 2010相同的功能,而用户无需管理可扩展性和安全协作解决方案所需的硬件和软件。在本文中,我会通过构建在SharePoint Online中运行的解决方案,来概括SharePoint Online开发与SharePoint 2010开发的异同点。

随着SharePoint Online下一版本的发布,SharePoint开发人员将能够使用他们在SharePoint 2010里使用的相同技能和工具来开发协作方案,这些工具和技能包括 Visual Studio 2010, SharePoint Designer 2010, C#Visual Basic以及SharePoint API SDK。在开发内部部署的SharePoint和开发云端的SharePoint有很多共同点,但是同样也有很多显著的差异会影响你如何构建解决方案。

了解这些差异将有助于您了解哪些解决方案可以在SharePoint Online里创建并运行,以及如何开发这些解决方案。

自定义SharePoint Online的相似点

SharePoint 2010的开发中,您可以通过使用浏览器和SharePoint Designer 2010来自定义SharePoint,并通过使用Visual Studio 2010生成解决方案。而对于SharePoint Online来说,通过浏览器和SharePoint Designer 2010来进行自定义与SharePoint 2010版本大致相同(鉴于下一节所述的功能差异)。使用Visual Studio 2010开发SharePoint Online解决方案也大体相同。通过其中迭代开发的集成调试体验,在Visual Studio 2010中的开发基于SharePoint 2010的本地实例,(无论运行在Windows 7Windows Server 2008 R2的本地机或虚拟机(VM)中)。开发完成后,该解决方案通过SharePoint 2010同样提供的解决方案库,被上传到SharePoint Online中。

自定义SharePoint Online的关键差异

尽管SharePoint Online建立在SharePoint 2010的基础上,但当您在开发SharePoint Online的解决方案时,仍有一些关键差异需要您牢记。首先,SharePoint Online只支持网站和Web范围的解决方案。它运行在多租户云中,多租约运行在一个共享的数据库基础架构中,所以Farm范围(功能在这整个Farm范围内被激活)的解决方案不被支持也并不奇怪。同样,在SharePoint Online中,您的SharePoint租赁最高访问级别为网站集级别,所以Web应用范围的功能(功能在一个Web应用中的每个Web站点中运行)也不被支持

其次,SharePoint Online只支持部分信任的解决方案。完全信任的解决方案,也就是那些访问权限超出网站级别,或者可以授权以管理员级别运行Farm上的解决方案也不受支持

最后,尽管SharePoint Online是建立在SharePoint 2010的基础上,但它和内部服务器部署的2010版在功能上并没有百分百的相同。如欲了解SharePoint 2010SharePoint Online的完整功能比较,请参阅微软SharePoint Online测试版服务说明,您可从bit.ly/bBckolOffice 365测试版服务说明中获取有关信息

功能列表显示大多数的SharePoint自定义功能都受支持。不支持业务连接服务(BCS,外部列表和从SharePoint
Online
外部调用Web服务(不在部分信任的解决方案中被支持)将会对构建运行在SharePoint Online的解决方案造成巨大影响。不过,我们有计划在将来发布的版本中支持BCS服务。

了解了这些异同点后,让我们看看一些解决方案的示例。您可以在SharePoint
Online
中生成这些类型的解决方案并运行,这包括了沙盒解决方案和SharePoint客户端对象模型(OM)。其他类型的解决方案,例如通过声明式工作流解决方案将业务流程自动化等,将在以后的文章中介绍。

用沙盒解决方案开发SharePoint Online

在上节中,您了解到SharePoint
Online解决方案必须限于站点或Web范围的功能,数据访问限定于站点范围的集合,且必须在部分信任环境中运行。开发以沙盒模式运行的解决方案符合所有这些条件,同时让SharePoint
Online管理员可以直接将解决方案上传到解决方案库,从而实现轻松部署。

Visual Studio 2010为沙盒解决方案提供了极大支持,其中包括项目模板和项目项模板支持,创建新项目为沙盒解决方案的SharePoint自定义向导,站点集范围的SharePointAPIIntelliSense支持,以及调试和打包支持。若要开始构建SharePoin Online解决方案,你需要开发并调试作用在本地SharePoint 2010的解决方案。你需要在安装SharePoint
2010Visual Studio 2010的同时,安装64位的Windows 7Windows Server 2008 R2 。另一个着手构建解决方案的好办法是使用Information Worker Demonstration and Evaluation Virtual Machine
RTM)。它提供了虚拟化的SharePoint
2010开发环境(从
bit.ly/ezfe2Y 下载)。我也推荐Visual Studio SharePoint 2010 Power Toolsbit.ly/azq882) ,它增加了沙盒和沙盒模式的可视Web部件项目项模板的编译时支持。

在本文的示例中,我将运用下面的这个简单场景来构建解决方案:即为虚拟的Contoso公司员工提供他们采购系统所不支持的采购申请功能。首先,我会在内部部署的SharePoint 2010开发环境中创建一个站点集和站点。我使用的是前面提到过的虚拟机,因此我创建了http://o365dpe.contoso.com/sites/spomsdnmag/purchasing。我的第一个解决方案会部署一个用来追踪这些非标准化购买的列表。我会打开Visual Studio 2010,选择文件|新项目,并在新建项目对话框中选择“空白的SharePoint项目”,然后将该项目命名为 PurchasingMgr

SharePoint自定义向导对话框中,我将在“what local site… (您想使用哪个地方站点进行调试) 一项中键入我站点的URLhttp://o365dpe.contoso.com/sites/spomsdnmag/Purchasing/,选择“部署为沙盒解决方案”,然后点击“完成”,如图一所示。

1 制定PurchasingMgr的站点和信任级别

接下来,我会在解决方案资源管理器中选择PurchasingMgr项目,右击并选择“添加新项目”。在“添加新项目”
对话框中,我会在已安装的模板节点中选择
SharePoint 2010支持的SharePoint项模板。不是所有这些模板都支持沙盒解决方案,所以那些模板在SharePoint Online中也并非都被支持。图2显示了支持沙盒解决方案的项目模板。

2 在沙盒解决方案中支持的项目模板

项模板

是否兼容沙盒?

备注

可视Web 部件

需要在SharePoint 服务器上安装ASCX 文件

可视Web 部件 (沙盒模式)

通过安装 Visual Studio 2010 SharePoint Power Tools提供此项功能

Web 部件

顺序工作流

要求将工作流解决方案部署为Farm解决方案

状态机工作流

要求将工作流解决方案部署为Farm解决方案

业务数据连接模型

需要将BCS解决方案部署为完全信任的解决方案 ;这是在 SharePoint Online 中不支持的功能

应用程序页

需要将 ASPX 页面部署到
SharePoint 服务器

事件接收器

模块

内容类型

通过内容类型添加的列表定义

列表定义

列表实例

空元素

用户控件

需要在 SharePoint 服务器上安装的 ASCX 文件

为了生成我的列表,我将选择内容类型项模板来定义站点列和内容类型,并键入NonStandBusPurchaseRequestsCT作为名字。

SharePoint
自定义向导中,我会选择“项”作为基础内容类型,然后单击“完成”。内容类型将包含一个标题列,一个描述列和一个价格列。我会通过替换用XML创建的Elements.xml中的内容(图3种)来声明定义这些内容类型。

3
通过Elements.xml
定义NonStandBusPurchaseRequestsCT

<?xml
version=”1.0″ encoding=”utf-8″?>

<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>

<Field SourceID=”http://schemas.microsoft.com/sharepoint/v3″

ID=”{A74E67E5-8905-4280-90C9-DEBFFC30D43D}”

Name=”RequestDescription”

DisplayName=”Description”

Group=”Purchasing Manager Custom Columns”

Type=”Note”

DisplaceOnUpgrade=”TRUE” />

<Field SourceID=”http://schemas.microsoft.com/sharepoint/v3″

ID=”{CB5054F5-0C60-4DBE-94D2-CEFBFB793C7F}”

Name=”Price”

DisplayName=”Price”

Group=”Purchasing Manager Custom Columns”

Type=”Currency”

DisplaceOnUpgrade=”TRUE” />

<!– Parent
ContentType: Item (0x01) –>

<ContentType ID=”0x010078a81c8413f54917856495e56e7c09ed”

Name=”Purchasing Manager – Non-Standard Business Purchase
Requests Content Type”

Group=”Purchasing Manager Content Types”

Description=

“Non-Standard
Business Purchase Requests Content Type

for the
Purchasing Manager Solution”

Inherits=”TRUE”

Version=”0″>

<FieldRefs>

<FieldRef ID=”{fa564e0f-0c70-4ab9-b863-0177e6ddd247}” Name=”Title”

DisplayName=”Title” />

<FieldRef ID=”{A74E67E5-8905-4280-90C9-DEBFFC30D43D}”

Name=”RequestDescription”

Required=”TRUE” />

<FieldRef ID=”{CB5054F5-0C60-4DBE-94D2-CEFBFB793C7F}” Name=”Price”

Required=”TRUE” />

</FieldRefs>

</ContentType>

</Elements>

接下来,我将在解决方案资源器中右击PurchasingMgr并选择“添加新项目”,来定义基于该内容类型的列表。我将选择项模板“通过内容类型添加的列表定义”,并命名列表定义为NonStandBusPurchaseRequestsListDefn,然后单击“添加”。

SharePoint 自定义向导中,我会选择之前 创建的内容类型,并选中“添加列表实例”。为NonStandBusPurchaseRequestsListDefn创建的Elements.xml如图4所示。

4 通过Elements.xml 定义NonStandBusPurchaseRequestsListDefn

<?xml
version=”1.0″ encoding=”utf-8″?>

<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>

<!– Do not change
the value of the Name attribute below.

If it does not
match the folder name of the List Definition project item,

an error will
occur when the project is run. –>

<ListTemplate

Name=”NonStandBusPurchaseRequestsListDefn”

Type=”10051″

BaseType=”0″

OnQuickLaunch=”TRUE”

SecurityBits=”11″

Sequence=”410″

DisplayName=”Purchasing Manager –

Non-Standard
Business Purchase Requests List Definition”

Description=

“Non-Standard
Business Purchase Requests List Definition

for the
Purchasing Manager Solution”

Image=”/_layouts/images/itgen.png”/>

</Elements>

请注意,在我创建的功能里的每个列表定义都需要通过一个大于10000的唯一类型值来辨别(以避免与定义在SharePoint中的列表冲突),而且我使用这个值来定义基于那个列表定义的任何列表实例。

要将自定义列表添加到列表视图中,我将打开创建的Schema.xml,并将FiledRef元素添加到默认视图中,如5所示

5 添加自定义列表到NonStandBusPurchaseRequestsListDefn默认视图中

<View BaseViewID=”1″ Type=”HTML” WebPartZoneID=”Main”

DisplayName=”$Resources:core,objectiv_schema_mwsidcamlidC24;”

DefaultView=”TRUE” MobileView=”TRUE”
MobileDefaultView
=”TRUE”

SetupPath=”pages\viewpage.aspx” ImageUrl=”/_layouts/images/generic.png”

Url=”AllItems.aspx”>

<Toolbar Type=”Standard”
/>

<XslLink Default=”TRUE”>main.xsl</XslLink>

<RowLimit Paged=”TRUE”>30</RowLimit>

<ViewFields>

<FieldRef Name=”Attachments”>

</FieldRef>

<FieldRef Name=”LinkTitle”>

</FieldRef>

<FieldRef ID=”{A74E67E5-8905-4280-90C9-DEBFFC30D43D}”

Name=”RequestDescription” />

<FieldRef ID=”{CB5054F5-0C60-4DBE-94D2-CEFBFB793C7F}” Name=”Price”
/>

</ViewFields>

<Query>

<OrderBy>

<FieldRef Name=”ID”>

</FieldRef>

</OrderBy>

</Query>

<ParameterBindings>

<ParameterBinding Name=”NoAnnouncements”

Location=”Resource(wss,noXinviewofY_LIST)” />

<ParameterBinding Name=”NoAnnouncementsHowTo”

Location=”Resource(wss,noXinviewofY_DEFAULT)” />

</ParameterBindings>

</View>

最后,我将定义列表中的一个实例。我选择位于NonStandBusPurchaseRequestsListDefn下的ListInstance1并命名其为NonStandBusPurchaseRequestsListInstance。我会打开Elements.xml,通过添加以下XML来使列表基于内容类型,并为用户提供帮助性说明:

<?xml
version=”1.0″ encoding=”utf-8″?>

<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>

<ListInstance Title=”Non-Standard
Business Purchase Requests”

OnQuickLaunch=”TRUE”

TemplateType=”10051″

Url=”Lists/NonStandBusPurchaseRequestsListInstance”

Description=

“Non-Standard
Business Purchase Requests List

for the
Purchasing Manager Solution”>

</ListInstance>

</Elements>

Visual Studio 2010中,我会选择“调试”,然后开始调试来测试解决方案。此解决方案被打包并部署到内部部署的网站,如图6所示。

6 调试PurchasingMgr 解决方案

我已经测试了PurchasingMgr方案,我现在可以将其部署到SharePoint Online上了。我将使用工作组站点模板在SharePoint Online上创建一个新的站点集,将其命名为Purchasing。回到Visual Studio 2010中,我会在项目资源管理器中右击PurchasingMgr项目并选择“打包”来打包解决方案。要将解决方案部署到SharePoint
Online,我只需要将其上传到解决方案库并激活站点功能(我需要站点集管理员权限来实现此操作)。要做到这一点,我要登陆SharePoint Online,定位到我的站点集,选择“站点操作
|站点设置”,再选择“解决方案”来访问解决方案库。在解决方案库中,我将单击“解决方案”选项卡,在功能区选择“上传解决方案”,然后在bin/Debug中浏览PurchasingMgr.wsp文件并单击OK,然后激活。你会看到您的解决方案在解决方案库中,如7所示。

7 PurchasingMgr部署到SharePoint Online

接下来,为了激活包含我的网站列,内容类型和列表的功能,我会定位到Purchasing站点并选择站点操作|站点设置|管理站点功能。我会选择Purchasing
Manager(采购经理)内容类型和列表功能,并选择激活。此时您应该会在SharePoint
Online站点看见非标准业务采购请求列表。

Purchasing Manager(采购经理)只是您在SharePoint
Online中利用沙盒解决方案可以完成的其中一个例子。牢记沙盒解决方案的限制,以及SharePoint
Online所支持的功能的限制,你就可以创建能在SharePoint
2010SharePoint Online运行的解决方案。

Silverlight创建客户端解决方案

SharePoint 2010引入了客户端OM。。它为使用运行在远程机器(包括Silverlight
ECMAScript的浏览器)的Microsoft
.NET Framework Silverlight
ECMAScript(包括JavaScript JScript)来构建的SharePoint客户端提供了面向对象和面向客户端的API。该APIMicrosoft.SharePoint服务器端的命名空间是保持一致的,因此学习起来很容易。该API在受支持的客户端类型中也是保持一致的,因此将知识应用于不同的客户端解决方案中也很容易。客户端OM
APISharePoint Online支持。对于云开发,它也是一个很有价值的工具。

比如,我可以使用客户端OM创建一个Silverlight 4应用程序,将项目添加至我的列表中,并托管此应用程序在沙盒Web部件中。为此,我将打开Visual
Studio 2010,选择文件
|新项目,并在新项目对话框中选择“清空SharePoint项目”。我将项目命名为PurchasingMgrWP并单击OK。我会再次创建此解决方案为沙盒解决方案并使其指向我内部部署的Purchasing站点中。为了创建Silverlight
4应用程序,我会右击PurchasingMgrWP解决方案,在已安装模板下选择Silverlight,选择Silverlight应用程序并将解决方案命名为NonStandBusPurchaseReqsSLOM。在新的Silverlight应用程序对话框中,我会取消“在新Web站点中托管Silverlight应用程序”对话框(我们将通过在SharePoint中托管应用程序来进行测试)并选择Silverlight版本为Silverlight 4

若要引用Silverlight客户端OM API ,我会将Microsoft.SharePoint.Client.Silverlight.dllMicrosoft.SharePoint.Client.Silverlight.Runtime.dll的引用添加到项目中。这两个程序集位于C:\Program
Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin中。接下来,我将打开MainPage.xaml来创建Silverlight UI,并用8的代码替换XAML

8 NonStandBusPurchaseReqsSLOM MainPage.xaml

<UserControl xmlns:sdk=”http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk”

x:Class=”NonStandBusPurchaseReqsSLOM.MainPage”

xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”

xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″

xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″

mc:Ignorable=”d”

d:DesignHeight=”300″ d:DesignWidth=”400″>

<Grid x:Name=”LayoutRoot” Background=”White”>

<Grid.ColumnDefinitions>

<ColumnDefinition />

<ColumnDefinition />

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition Height=”Auto”/>

<RowDefinition Height=”Auto”/>

<RowDefinition Height=”Auto”/>

<RowDefinition Height=”Auto”/>

</Grid.RowDefinitions>

<sdk:Label Content=”Title:” Grid.Column=”0″ Grid.Row=”0″ Margin=”3″/>

<sdk:Label Content=”Description:” Grid.Column=”0″ Grid.Row=”1″ Margin=”3″/>

<sdk:Label Content=”Price:” Grid.Column=”0″ Grid.Row=”2″ Margin=”3″/>

<TextBox Name=”Title” Grid.Column=”1″ Grid.Row=”0″ Margin=”3″/>

<TextBox Name=”Description” Grid.Column=”1″ Grid.Row=”1″ Margin=”3″/>

<TextBox Name=”Price” Grid.Column=”1″ Grid.Row=”2″ Margin=”3″/>

<Button Content=”Add” Grid.Column=”1″ Grid.Row=”3″ Margin=”3″

Name=”addNonStanPurchaseReq” HorizontalAlignment=”Right”

Height=”25″ Width=”100″ Click=”addNonStanPurchaseReq_Click” />

</Grid>

</UserControl>

8中的XAML定义文本框和一个按钮来收集信息以添加到我的列表,如9所示

9 设计器中的 MainPage.xaml

双击设计器中的按钮,将类替换成10中的代码。

10 addNonStanPurchaseReq_Click

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using Microsoft.SharePoint.Client;

namespace NonStandBusPurchaseReqsSLOM

{

public
partial class MainPage : UserControl

{

private
string webUrl;

public
MainPage(string url)

{

webUrl = url;

InitializeComponent();

}

private
void addNonStanPurchaseReq_Click(object sender, RoutedEventArgs
e)

{

ClientContext
clientContext = new ClientContext(webUrl);

Web webSite =
clientContext.Web;

ListCollection
webLists = webSite.Lists;

List nonStandBusPurList =


clientContext.Web.Lists.GetByTitle(

“Non-Standard Business Purchase Requests”);

ListItem newListItem =


nonStandBusPurList.AddItem(new
ListItemCreationInformation());

newListItem[“Title”] = Title.Text;

newListItem[“RequestDescription”] =
Description.Text;

newListItem[“Price”] = Price.Text;

newListItem.Update();


clientContext.Load(nonStandBusPurList, list => list.Title);


clientContext.ExecuteQueryAsync(onQuerySucceeded, onQueryFailed);

}

private
void onQuerySucceeded(

object
sender, ClientRequestSucceededEventArgs args)

{


Dispatcher.BeginInvoke(() =>

{

MessageBox.Show(“New
item added.”
);

});

}

private
void onQueryFailed(object
sender,


ClientRequestFailedEventArgs args)

{


Dispatcher.BeginInvoke(() =>

{

MessageBox.Show(“Request
failed. “
+ args.Message + “\n”
+

args.StackTrace);

});

}

}

}

10中的代码遵循了客户端OM代码的通用模式。首先,我将通过ClientContext类(相当于SPCContext类)访问客户端上下文。接下来,我将分别通过WebListCollectionList类分别访问站点和列表。请注意SPWeb,
SPListCollection SPList类之间的相似点。最后,我将通过调用List.AddItem方法创建一个ListItem,将用户界面中的数据填充进去并调用ListItem.Update方法。只有当调用ClientContext.Load
ClientContext.ExecuteQueryAsync方法来执行查询时,ListItem才真正被创建。请注意您可以通过ClientContext.Load并调用ClientContext.ExecuteQueryAsync方法加载多个查询,从而节省了到服务器之间的往返。

为了部署Silverlight 4应用程序,我会添加一个板块来和我的Web Part

项目一起部署应用程序。我会在解决方案资源管理器中选择PurchasingMgrWP,右击并选择添加新项目|模块,将模块命名为ClientBin。我将使用以下XML来替换新创建的Elements.xml中的内容:

<?xml version=“1.0” encoding=“utf-8”?>

<Elements xmlns=“http://schemas.microsoft.com/sharepoint/”>

<Module Name=“ClientBin”>

<File Path=“ClientBin\NonStandBusPurchaseReqsSLOM.xap”

Url=“ClientBin/NonStandBusPurchaseReqsSLOM.xap”
/>

</Module>

</Elements>

XMLNonStandBusPurchaseReqsSLOM.xap 文件部署到SharePoint 站点的ClientBin文件夹中。

为使用ClientBin模块部署NonStandBusPurchaseReqsSLOM项目的输出内容,我将在解决方案资源管理器中选择ClientBin模块,并打开“项目输出引用”属性对话框。我将单击“增加”,选择NonStandBusPurchaseReqsSLOM作为项目名称,并选择ElementFile作为部署类型。

接下来,我会将自定义Web部件添加到我的SharePoint解决方案中,来承载我的Silverlight
4应用程序。我会在解决方案资源管理器中选择PurchasingMgrWP,右击并选择添加|新项目,选择Web部件并将其命名为NonStandBusPurchaseReqsWP。为了将参数传递给我的Silverlight
4应用程序(例如一个用来创建ClientContext的站点的URL),我将使用一个自定义Web部件。为此,我会添加一个名为SilverlightObjectTagControl.cs的帮助类,并用11的代码替换类的代码体。

11 添加SilverlightObjectTagControl.cs帮助类

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

namespace PurchasingMgrWP

{

class
SilverlightObjectTagControl : WebControl

{

public
string Source { get;
set; }

public
string InitParameters { get; set; }

protected
override void
CreateChildControls()

{

base.CreateChildControls();

if
(Source != null && Source != “”)

{

string
width = (this.Width == Unit.Empty) ? “400” :

this.Width.ToString();

string
height = (this.Height == Unit.Empty) ? “300” :

this.Height.ToString();

this.Controls.Add(new LiteralControl(


<div>”
+


<object data=\”data:application/x-silverlight-2,\” +


type=\”application/x-silverlight-2\” width=\””
+
width +


\” height=\”” +
height + “\”>” +


<param name=\”source\” value=\””
+ Source + “\”/>” +


<param name=\”onerror\” value=\”onSilverlightError\”
/>”
+


<param name=\”background\” value=\”white\” />”

+


<param name=\”minRuntimeVersion\” value=\”4.0.50826.0\”
/>”
+


<param name=\”autoUpgrade\” value=\”true\” />”

+


<param name=\”initparams\” value=\””
+
InitParameters + “\” />” +


<a href=\”http://go.microsoft.com/fwlink/?LinkID=”
+


149156&v=4.0.50826.0\” +


style=\”text-decoration: none;\”>”
+


<img src=\”http://go.microsoft.com/fwlink/?LinkId=161376\” +


alt=\”Get Microsoft Silverlight\” style=\”border-style:
none\”/>”
+


</a>”
+


</object>”
+


<iframe id=\”_sl_historyFrame\” +


style=.visibility:hidden;height:0;width:0;border:0px.></iframe>”

+


</div>”

));

}

}

}

}

11中的SilverlightObjectTagControl有两个属性:Source用来向Web部件传递Silverlight应用程序的URL,从而可以在Web部件中加载该Silverlight应用程序;InitParameter用来将初始参数传递到Silverlight
4应用程序中。在CreateChildControls方法中,这些属性被用于为Silverlight应用程序生成<object
/>标签。若要使用这个类,打开NonStandBusPurchaseReqsWP.cs,并将该类中的代码替换成12的代码。

12 NonStandBusPurchaseReqsWP.cs

using System;

using System.ComponentModel;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using
System.Web.UI.WebControls.WebParts;

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

namespace
PurchasingMgrWP.NonStandBusPurchaseReqsWP

{

[ToolboxItemAttribute(false)]

public
class NonStandBusPurchaseReqsWP
: WebPart

{

protected
override void
CreateChildControls()

{

base.CreateChildControls();


SilverlightObjectTagControl slhc =

new SilverlightObjectTagControl();

slhc.Source =
SPContext.Current.Site.Url +

“/ClientBin/NonStandBusPurchaseReqsSLOM.xap”;

slhc.InitParameters = “url=” + SPContext.Current.Web.Url;

this.Controls.Add(slhc);

}

}

}

12中的代码创建了一个SilverlightObjectTagControl实例,将Source属性设为在ClientBin
中的Silverlight应用程序URL,并设置InitParameter来保存现有站点的URL(非标准业务购买请求列表可在此找到)。要将URL传递到NonStandBusPurchaseReqsSLOM中的MainPage类构造器中,打开App.xaml.cs,并为Application_Startup事件添加以下代码:

private void
Application_Startup(object sender,

StartupEventArgs e)

{

string
url = e.InitParams[“url”];

this.RootVisual
= new MainPage(url);

}

若要测试Web Part ,将PurchasingMgr.wsp包部署到内部部署的Purchasing站点来部署非标准业务购买请求列表(该列表在之前提到的调试阶段结束的时候被移除),然后从Visual
Studio 2010中调试PurchasingMgrWP解决方案。当Web 部件被添加到\Purchasing\Home.aspx中时,它允许我将项目从Silverlight直接添加到列表中,如1314所示

13 运行中的NonStandBusPurchaseReqsWP

14 更新后的非标准业务购买请求列表

开发和调试内部部署站点使我能使用Visual
Studio 2010来同时调试SharePointSilverlight 4,直到我将解决方案全部测试完毕为止。这时,我会上传PurchasingMgrWP.wspSharePoint Online的解决方案库中。

SharePoint客户端OM提供了我们所熟悉而统一的面向对象的API来访问SharePoint Online的列表和库。此APIMicrosoft.SharePoint API的一个子集,并限于站点集及更小的范围,这点与SharePoint
Online的开发要求很完美达统一起来。

云中的SharePoint解决方案

总的来说,SharePoint Online为开发者提供了一个独特的机会来运用他们已有的技术和工具去构建面向云的SharePoint解决方案。通过了解SharePoint Online自定义功能(包括支持和不支持哪些内容),沙盒解决方案,SharePoint客户端OMSharePoint Designer 2010构建的声明性工作流,您可以使用SharePoint Online生成可在云运行的SharePoint解决方案。在测试版本过程中,如您欲了解更多的SharePoint Online的开发信息,请查看SharePoint
Online Developer资源中心
msdn.com/sharepointonline)

使用带有选项域的LINQ-to-SharePoint (Ricky Kirkham)

[原文发表地址]Using LINQ-to-SharePoint with Choice Fields (Ricky Kirkham)

[原文发表时间]3 May 2011 7:00 AM

如果你们喜欢使用LINQ to SharePoint提供程序来执行服务器端代码数据查询的话,迟早会遇到在LINQ查询强制类型的世界和SharePoint的分散本质之间产生的一种冲突。要使用LINQ查询,源代码必须包括一个对象关系映射,就是将列表和内容类型转换为类,把字段转换成内容类型类的强类型属性。这个代码是由SPMetal工具生成的。但是当解决方案部署之后,网站拥有者仍然可以添加新列表。在对象关系映射中这些新添加的列表并没有被包括进去。类似地,新的字段也可以被添加到网站和列表中。在对象关系映射中这些也并没有被包括。

当然,如果你们的LINQ查询及数据更改仅涉及到那些在设计阶段生成对象关系映射时出现的列表,内容类型和字段,新实体的存在并不会造成问题。但是有时候设计时对象关系映射和运行阶段被查询的网站内容的不匹配会给LINQ工作带来问题。许多这类问题可以通过用Extending the
Object-Relational Mapping
中介绍的扩展对象关系映射技术来解决。本篇博客中,我想描述一个问题并提出一个在后面的文章中不会提到的解决方案。

 

SPMetal为一个选项字段生成代码时,它将会创造一个枚举类型来表示该字段可能的值。例如,下面的代码是为标准的任务列表上的标准优先级域生成的:

public enum Priority : int

{

None = 0,

Invalid = 1,

[Microsoft.SharePoint.Linq.ChoiceAttribute(Value = “(1) High”)]

_1High = 2,

[Microsoft.SharePoint.Linq.ChoiceAttribute(Value = “(2) Normal”)]

_2Normal = 4,

[Microsoft.SharePoint.Linq.ChoiceAttribute(Value = “(3) Low”)]

_3Low = 8,

}

但是如果列表拥有者把“(4)
Trivial”
作为一个额外的可能选项添加到优先级列的定义中,会发生什么? 对于在优先级域具有新值的任务项目,一个 LINQ查询会返回“Invalid”而不是“(4)
Trivial”
作为字段的值

 

问题的本质是,可以被最终用户修改的数据架构是固有的弱类型,但是对象关系映射将一个强类型束缚施加到架构上。为了解决这个问题,我们需要放松那个束缚;也就是,我们需要削弱,从enum转换到string的选择字段类型;但是不要削弱得太多。

 

一个简单的解决方案,但并不总是适用

 

如果你们想要做的都是查询数据,SPMetal工具的可配置性提供了一个简单解决方案。通过使用命令行调用SPMetal中关联的parameters.xml文件,可以修改工具的默认行为。如何这么操作的详细情况请参考SPMetalOverriding SPMetal Defaults by Using a Parameters XML File。在这种情况下,让SPMetal把优先级域看作是一个字符串而不是具有parameters.xml文件的枚举,如下所示:

<?xml
version=”1.0″ encoding=”utf-8″?>

<Web xmlns=”http://schemas.microsoft.com/SharePoint/2009/spmetal“>

<ContentType Name=”Task”
Class=”Task”>

<Column Name=”Priority” Member=”Priority” Type=”String” />

</ContentType>

<ExcludeContentType Name=”Summary
Task”/>

</Web>

补充:你也会注意到我把任务摘要内容类型从对象关系映射中删除了,这是为了避免再次做我的方案中一些不得不做的琐事,因为任务摘要内容类型也有优先级域。

通过这个正在使用的parameters.xml文件,SPMetal将会为Task类的优先级属性创建下面的签名:

public String
Priority

以下签名相反,它会默认创建的。public System.Nullable<Priority> Priority

补充:优先级域也在标准团队网站作为站点列,因此SPMetal将仍然会生成枚举来保存为站点列的类型,但是它也不会使用枚举作为任务内容类型中的优先级列类型。

现在你的LINQ查询将会返回“(4)
Trivial”
或其他添加到优先级列定义的选项,而不是“Invalid”

什么时候你也想要写到选项域

当你要用LINQ-to-SharePoint提供者写数据并查询该数据时怎么办? (你可以参考How to: Write to
Content Databases Using LINQ to SharePoint
来操作)既然已经弱化了优先级域的类型,那么代码就可以将任意字符串写到域中了,即使是一个不在选项列表定义列中的字符串。你可以保证你也可以写在写到选项域之前检查可能有的选项列表的代码,但是你不想每次用LINQ
to SharePoint
提供商写到选项域时去重写那些代码。确保必要的确认每次都执行的一个方法就是把确认代码放在代表选项域属性的设置函数里。下面介绍一种方式,你可以做到这一点

首先你需要做的是删除SPMetal生成的文件中的声明且实现属性的代码。如果不这样做的话,当SPMetal生成代码时那个属性中的设置函数的自定义会被覆盖,你也不会知道你将再也不能重新生成代码了。

幸好,SPMetal生成的类是用partial关键字标记的。那意味着在另一个代码文件中你可以重新声明类,并也可以向新文件中的类添加额外成员。

继续Tasks列表及优先级列中的例子,进行这些步骤:

1. 在有Tasks列表的站点上指出SPMetal,生成你的代码

2. Visual Studio项目中添加一个新类代码文件。删除自动生成的子类声明,也删掉命名空间声明。

补充:由SPMetal生成的代码文件没有声明一个命名空间,这意味着Visual
Studio
项目的默认命名空间是设想的。如果你在两个代码文件中定义了一个分部类,一个并没有把类放到明确的命名空间声明中,那么另一个代码文件也就不能把类放到明确的命名空间声明中,甚至明确声明的默认的命名空间也不行。这似乎是编译器处理分部类的一个怪癖。因此,你必须删除Visual
Studio
自动包括在新类代码文件中的那个明确的命名空间声明。

3. Microsoft.SharePointMicrosoft.SharePoint.Linq添加using语句。

4. 将生成的代码中Task类声明的签名复制到你的新文件中,添加打开及关闭大括号。(不要复制上面类的声明属性)

public partial class
Task : Item {

}

5. 在生成的代码中复制优先级属性支持的字段,然后把它粘贴到新文件的Task类中。如果之前你已经将简单的解决方法(上面提到过)应用到这个项目中了,那么支持子段的声明将会是:

private String
_priority;

否则,它看起来应是:private System.Nullable<Priority> _priority;

6. 用同样的方法从生成的文件中把Priority类声明移到新文件中。这种情况下,你一定要复制声明上的属性。

[Microsoft.SharePoint.Linq.ColumnAttribute(Name = “Priority”, Storage =
“_priority”, FieldType =
“Choice”)]

public System.Nullable<Priority> Priority

{

get {

return this._priority;

}

set {

if ((value != this._priority)) {

this.OnPropertyChanging(“Priority”,
this._priority);

this._priority = value;

this.OnPropertyChanged(“Priority”);

}

}

}

同样,如果你已经把简单的解决方案应用到了这个项目中,那么属性的类型将是字符串类型,而不是System.Nullable<Priority>

7.
如果之前你没有把简单的解决方案应用到该项目,那么就需要在新文件中出现它的地方将System.Nullable<Priority>改为“String”。

8.
在两个文件中你不能声明相同的属性和支持字段。不像类那样,属性不能被标记为“partial”。因此,你要确保它们从生成代码文件中删除了,也不会在SPMetal以后的运行中再次生成。完成那个操作需要创建一个有下面内容的parameters.xml文件。

<?xml
version=”1.0″ encoding=”utf-8″?>

<Web AccessModifier=”Internal” xmlns=”http://schemas.microsoft.com/SharePoint/2009/spmetal“>

<ContentType Name=”Task”
Class=”Task”>

<ExcludeColumn Name=”Priority” />

</ContentType>

<ExcludeContentType Name=”Summary
Task”/>

</Web>

9.
用引用新的parameters.xml文件的命令行重新运行SPMetal。新生成的代码文件将不再包含优先级属性或它的支持字段的声明。

现在需要向选项字段类的设置函数添加你的验证逻辑。请采用下面的步骤继续操作。

1.
向上面的“if’声明的优先级属性添加下面的代码:

using (SPSite siteCollection = new SPSite(—– ????? —–))

{

using (SPWeb website = siteCollection.OpenWeb(—-
????? —–))

{

SPList taskList = website.GetList(this.Path);

SPFieldChoice priorityField
= taskList.Fields[“Priority”] as SPFieldChoice;

if (!priorityField.Choices.Contains(value))

{

throw new ArgumentOutOfRangeException(“value”,
String.Format(“‘{0}’ is not a possible value for
the Choice field ‘Priority’ in the ‘Tasks’ list.”, value));

}

}

}

从底部开始,注意这个代码的后面。如果通过调用代码的值没有在SPFieldChoice对象的选项集合中,那么就会抛出一个异常。从SPList对象的字段集合中获取字段对象的引用和对后者对象的引用,反过来,后者对象的引用通过SPWeb对象的GetList方法和Task对象的Path属性被获取。

前此任何一个都可以做,但是,代码需要引用SPWebSPSite对象。如果代码运行那里有一个HTTP文本环境中和一个非空的SPContext对象,代码也许会从SPContext对象中获得当前的SPSiteSPWeb对象。先让我们试着写些能用在操作台应用程序或其他没有HTTP环境的场景中的代码。

2.
要为SPWeb对象获取一个引用,需要一个针对网站的site-collection-relativeURL你可以通过启动任务对象的Path属性来构建URL以及从它的列表的网站相对URL的末尾做修剪。因此添加下面几行:

String webRelativeListURL
= “/Lists/Tasks”;

String siteRelativeWebURL = this.Path.Remove(this.Path.LengthwebRelativeListURL.Length);

3.
siteRelativeWebURL作为参数插入到OpenWeb方法中。

你需要从父网站集合的绝对URL来获取一个对SPSite对象的引用。这比较困难。Task类的Path属性不包括网站集合的URL的协议或域的一部分。在SPMetal生成的Task类中任何其他成员也没有这条信息。你需要做的是创建Task类的一个新成员,它可以保存这些信息,并当创建Task对象后可以初始化。参考下面的步骤继续:

1.
在你的代码文件(不是生成的代码文件)中,向Task类添加一个内部域的声明。

internal String parentDataContextWebURL;

你可以思考一会儿我们为什么要给它取那个名字。现在需要注意的是将要保存的是构造SPSite所需URL

2.用新域名代替SPSite架构中的参数—–
?????
—–parentDataContextWebURL.

内容类型类有一个由SPMetal生成的构造函数,这是SPMetal行为的一部分,不能被关掉或更改。因此不能自定义这个构造函数来初始化新的内部字段(因为你的自定义在代码重新生成时会被覆盖)。况且在你自己的类的部分定义中创建另一个构造函数不起任何作用。这是因为你的LINQ代码不能直接调用构造列表对象和它里头的项目。而是这些实体被DataContext对象的GetList方法创建。反过来那个方法调用生成的构造函数那个你不能修改的构造函数。

在生成的代码中你会发现内容类型类构造函数没有调用部分方法OnCreated,因此在你自己的分部类定义中可以实现这个方法。不幸的是这个方法不带参数(也没有调用它的构造函数),因此没办法传递你可能在初始化新域所需的数据。(同样,如果有一个HTTP环境,也许我们还可以从那里获得所需的信息,但是我们现在正在试着写能在没有这样的环境也可以运行的选项域验证代码。)

你需要做的是覆写DataContext对象的GetList方法,以使在返回到列表之前它就初始化每个列表对象的新域。可以这样做的原因是SPMetal生成的DataContext派生类也是被标记为Partial,按照下面的步骤继续:

1.
靠近生成的代码文件上部的是DataContext派生类的声明。把那个声明复制到你之前创建的新代码文件,然后添加打开和关闭大括号。这个类的名字是由你作为对SPMetal命令行调用/ code参数值来决定的。

public partial class LinqChoiceFieldExperimentsDataContext : Microsoft.SharePoint.Linq.DataContext
{

}

2.
向类中添加下面DataContext.GetList方法的重载。

public override EntityList<T> GetList<T>(string
listName)

{

EntityList<T> list = base.GetList<T>(listName);

if (typeof(T).Name == “Task”)

{

foreach (T t in list)

{

Task task = t as Task;

task.parentDataContextWebURL = this.Web;

}

}

return list;

}

注意将DataContext对象的Web属性(它保存了对象的绝对URL)传递到列表中每个Task对象的内部子段的方法,反过来,是用你的自定义设置函数来创建一个SPSite对象。顺便说下,这个URL也许是网站集合的一个子站的URL那样不会产生任何问题。SPSite构造函数很聪慧的,它知道你真正想要的是在传递到构造函数中的参数中实体的父SPSite

确实是那样。比如下面的,调用函数将会阻止无效的值写到选项域中。

using (LinqChoiceFieldExperimentsDataContext lCFDC
= new LinqChoiceFieldDataContext(http://Contoso/Marketing/))

{

EntityList<Task> tasks = lCFDC.GetList<Task>(“Tasks”);

tasks.First().Priority = “(4) Trivial”;

lCFDC.SubmitChanges();

}

当然在它的现有版本中,这个代码仅适用于Tasks列表中的优先级列。设想推广它来解决所有列表的选项域。正如我大学数学教科书上说的一样:“这是留给读者的练习”。

 

公布:SharePoint Diagnostic Studio

[原文发表地址] Announcing the SharePoint Diagnostic Studio

[原文发表时间]

维护SharePoint部署最具挑战的方面之一是了解为什么部属环境中会出现某些事件,通常IT专业人士和开发人员只有在事件发生和分配时才能着手研究,并通过分析性能计数器,事件和诊断日志,或通过对Usage数据库执行Transact-SQL语句去了解在何种情况下发生了什么和为什么会发生这些事件。这些任务一般都是由一系列工具来完成的,例如Excel,日志分析器,SQL Server Management Studio和其他工具。而且,IT专业人员和开发者还要对相关信息进行整理并并浓缩成有意义的格式。这些任务颇具挑战。大型复杂的服务器farm环境还使得所有这些任务变得更加困难。

通常最方便的识别并解决发生在服务器farm环境中的问题的方法是使用SharePoint Health AnalyzerSystems Center Operations Manager

SharePoint Administration Toolkit的下个版本(v2.0)包括新的SharePoint Diagnostics Studio。支持这些流程和解决方案,除了以上提到的这些SharePoint
Diagnostics Studio还提供了第三层可以用来实现的方法。

SharePoint Administration Toolkit的新版本中,我们介绍了一个新的修正过的SharePoint Diagnostics Studio,它完全从之前的诊断工具包中分离出来。作为下一代的SharePoint 诊断工具,SharePoint Diagnostics Studio通过可视化和结构化的方式来呈现服务器的诊断信息,使开发人员和IT专业人员能够在SharePoint 2010环境中快速诊断并处理间歇性性能问题,可靠性和功能性等问题等。

SharePoint Diagnostics Studio对每个请求都提供了前所未有的深度解析,涵括了用最小的权限来远程访问的每台机器。这样的深度使用使IT专业人员或开发人员能够迅速鉴别并隔离问题,而不需要对支持底层环境的物理硬件请求访问权。

SharePoint Diagnostics Studio除了从Usage数据库收集信息,还收集整理了事件和诊断(ULS)日志,并通过图形用户界面,为影响部署的问题提供清晰、单一的视图。SharePoint
Diagnostics Studio提供了各种各样的报告,旨在解决最常见问题的需求,包括容量,性能,可用性,和使用情况等。这些报告可以独立使用或一起使用,来识别并隔离发生在SharePoint环境中问题。

SharePoint Diagnostics Studio提供的报告分为五类:

1.基本情况

2.容量

3.性能

4.可用性

5.使用情况

整合的搜索功能使我们可以快速洞察在生命周期的请求阶段就已经发生的问题。它允许IT专业人员或开发人员对最常见的标准进行搜索,包括日期和时间,相关联Id和源用户。

 

SharePoint Diagnostics Studio支持快照和导出功能,使我们可以提取离线信息。

根据当前上下文自动检索的帮助功能对每种报告的目的和如何使用提供了指导。

现在就请下载SharePoint Administration Toolkit,开始解决你的问题吧。

更多资料

SharePoint Diagnostics Studio文档:http://technet.microsoft.com/en-us/library/hh144782.aspx

通过MSBuild增加应用程序的版本值(Phil Hoff)

[原文发表地址] Incrementing the feature version through MSBuild (Phil Hoff)

[原文发表时间] 29 Apr 2011 6:10 AM

如果你们正在使用TeamBuild MSBuild创建SharePoint 工程,那么大家就可以给SharePoint应用程序的新版本自动地增加版本号了。

可以将下面的MSBuild示例代码添加到一个SharePoint工程文件(.csproj or .vbproj)中来使包中所有应用程序的版本号在封装之前立即自动增值。它在项目服务图表生成和实际清单生成之间插入一个自定义目标。然后目标调用一个自定义,内嵌的MSBuild任务获取每一个已经解决功能的设计器文件,打开它,更新它的版本属性,然后把它写回到磁盘。

 

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\SharePointTools\
        Microsoft.VisualStudio.SharePoint.targets" />
<UsingTask TaskName="IncrementFeatureVersion" 
           TaskFactory="CodeTaskFactory" 
           AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
 <ParameterGroup>
  <Features ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
 </ParameterGroup>
 <Task>
  <Reference Include="Microsoft.VisualStudio.SharePoint" />
  <Reference Include="Microsoft.VisualStudio.SharePoint.Designers.Models.Features" />
  <Using Namespace="System.IO" />
  <Using Namespace="Microsoft.VisualStudio.SharePoint.Features" />
  <Using Namespace="Microsoft.VisualStudio.SharePoint.Designers.Models.Features" />
  <Code Type="Fragment" Language="cs">
   <![CDATA[
   foreach (ITaskItem featureTaskItem in Features)
   {
    string fullPath = featureTaskItem.GetMetadata("FullPath");
       
    // Ensure the file is read-write (as it may be read-only if not checked out of SCC).
    File.SetAttributes(fullPath, File.GetAttributes(fullPath) & ~FileAttributes.ReadOnly);
        
    Log.LogMessage(String.Format("Feature: {0}", fullPath), MessageImportance.High);
 
    // Read the feature from the designer (*.feature) file.
    IFeature feature = FeatureManager.ReadFeature(fullPath);
 
    // If no version has been specified, assume 1.0 (no build or revision).
    Version oldVersion = feature.Version ?? new Version(1, 0);
 
    Log.LogMessage(String.Format("Old Version: {0}", oldVersion), MessageImportance.High);                               
            
    // Increment the build number or start at 1, if old version did not specify one.
    int newBuild = oldVersion.Build != -1 ? oldVersion.Build + 1 : 1;
 
    Version newVersion = null;
            
    if (oldVersion.Revision != -1)
    {
     // Create a new version using the existing revision.
     newVersion = new Version(oldVersion.Major, 
                              oldVersion.Minor, 
                              newBuild, 
                              oldVersion.Revision);
    }
    else
    {
     // Create a new version without a revision (as passing -1 for undefined will throw).
     newVersion = new Version(oldVersion.Major, oldVersion.Minor, newBuild);
    }
            
    feature.Version = newVersion;
 
    Log.LogMessage(String.Format("New Version: {0}", feature.Version), MessageImportance.High);      
 
    // Write the feature back to the designer (*.feature) file.
    FeatureManager.WriteFeature(feature, fullPath);         
   }
   ]]>
  </Code>
 </Task>
</UsingTask>
 
<PropertyGroup>
 <!-- Increment feature versions before packaging (i.e. before PerformEnumeration). -->
 <CreatePackageDependsOn>
  PerformIncrementFeatureVersion;
  $(CreatePackageDependsOn);
 </CreatePackageDependsOn>
</PropertyGroup>
 
<!--
 Increments the Version attribute of each packaged feature's manifest.
    
 Inputs:   @(Feature)
 Outputs:  None
      
 NOTE: The Feature ItemGroup is built by CreateSharePointProjectService, hence the target dependency.      
  -->
<Target Name="PerformIncrementFeatureVersion" DependsOnTargets="CreateSharePointProjectService">
  <Message Importance="High" Text="Incrementing feature versions..." />
  <IncrementFeatureVersion Features="@(Feature)" />

</Target>

 

 

 

 

 

国际保护基金会依靠SharePoint作为其数字营销战略的重要组成部分

[原文发表时间] Mar 16, 2011, 12:32 AM
国际保护基金会(Conservation International)是致力于为人类利益保持地球的健康与富饶的一个非政府组织。通过科技,政策和野外工作,国际保护基金会应用智能解决方案来保护我们赖以生存的资源。
3名专职人员组成的一个小型网络团队负责管理和生成Conservation.org的内容。他们通过生成网络页面和快速响应需求,为来自组织不同部门不同背景的20多名员工提供支持。非技术人员可以使用SharePoint创建他们的内容并提交给网络团队来进行审批,而不用将所有内容直接交手给网络团队。这种分散化授权的方法的一个好处是,员工可以迅速更正错误或作出重要改变,而不会遇到瓶颈。SharePoint为不同国家、不同语种的职员带来的便捷,以及根据他们各自技能差异对集群邮箱服务(CMS)操作的灵活性,让员工们都乐在其中。
非技术人员也能在接受极少量培训和网络团队参与的情况下,通过添加页面或子站点扩展他们分配到的部分。这就使得他们不仅能创造性地开发内容,也能使内容在国家或部门内的网站上实现。
网站的创建是通过门户解决方案,微软的数字营销金牌合作伙伴和门户以及协助的共同努力下实现的。