使用 SharePoint Online 为 Office 365 自定义 Web 服务





5.00/5 (1投票)
使用沙盒解决方案开发 Web 服务
引言
Office 365 是下一代云生产力服务,可为企业提供重要的功能,与本地解决方案相比,成本更低。
它将 Exchange Online、Lync Online、Office 工具和 SharePoint Online 的 2010 版本整合为面向各种规模组织的云服务。
特别是 SharePoint Online 提供了一个强大的业务协作平台,开发人员可以使用 Microsoft SharePoint Designer 2010 和 Microsoft Visual Studio 2010 等标准开发工具在此平台上构建解决方案。但是,从开发人员的角度来看,SharePoint Online 存在许多限制,我们需要修改标准的开发模式。
我们只能部署沙盒解决方案,这些解决方案会在 Web 部件和其他元素周围创建安全包装器,并在 SharePoint 对象模型方面存在一些限制。它们绝对不能修改或向文件系统添加任何文件,并且我们的所有代码都在单独的工作进程中运行,而不是在 w3wp.exe 中运行。此类解决方案有利有弊(它不需要应用程序池回收!),也有弊端(首先,它不支持权限提升)。本文讨论了阻止我们使用 SharePoint 沙盒解决方案部署任何 WCF 或“旧”ASMX 服务的相关问题。建议的解决方案克服了这一限制,通过一个简单的 ASPX 页面模拟 Web 服务,该页面返回 JSON 格式的数据,而不是标准的 text/html。
具体来说,我们创建了- 一个沙盒 Web 部件来封装服务的业务逻辑
- 一个自定义母版页,以消除输出响应中不必要的内容
- 一个 Web 页面来模拟 Web 服务终结点
- 一个 Web 页面来调用服务并展示其典型用法
创建沙盒 Web 部件
本文的重点不是创建复杂的业务逻辑或展示 SharePoint 服务器端对象模型的功能,而是尝试解释一种不同的 SharePoint 数据访问方法。
在演示中,我们将实例化这个简单的对象,其中包含有关子站点的一些信息。
public class Stats
{
public List<Site> Sites { get; set; }
}
public class Site
{
public string Title { get; set; }
public int ListsCount { get; set; }
}
使用 SharePoint 对象模型服务器端进行此操作非常简单:我们进行 for...each
迭代以获取站点标题和列表数量;而在客户端脚本中执行相同的操作可能会更复杂,因为需要异步调用。有关这些步骤的任何详细信息,我建议查看附件中的源代码(WSWebpart 功能)。
在填充对象属性后,我们需要将其序列化并创建 JSON 字符串以发送回客户端。有很多方法可以实现这一点,最简单的方法是使用 JavaScriptSerializer
,它包含在 .NET Framework 3.5 中(位于 System.Web.Extensions.dll 程序集中)。
Stats stats = new Stats();
...
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(stats);
自定义母版页
母版页必须非常简单,以便仅以 JSON 格式返回原始结果。因此,我们可以创建一个仅包含一个占位符的母版页。
<%@ Master language="C#" %>
<asp:ContentPlaceHolder id="PlaceHolderMain" runat="server">
</asp:ContentPlaceHolder>
这样,我们就去掉了所有通用的信息,如 JavaScript、CSS 和其他内容,从而获得了一个干净的页面。
简单的服务页面
现在,我们可以将具有服务实现的自定义沙盒 Web 部件添加到新页面中,并强制使用我们的母版页。为此,我们可以使用 SharePoint 2010 框架中包含的一个新控件:SPUserCodeWebPart
。MSDN 上的页面不包含任何示例,但是,要唯一标识 Web 部件所需的属性是:
AssemblyFullName
:用户代码 Web 部件程序集的完整名称(例如,WebServiceSandbox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bf13a1a9ef2c3dc4)。SolutionId
:解决方案的 ID。TypeFullName
:沙盒解决方案 Web 部件类型的完整名称。
$SharePoint.Project.AssemblyFullName$
和 SolutionId 的 $SharePoint.Package.Id$
。但是,对于 TypeFullName,没有特定的变量,但正如 MSDN 上这篇详细的文章和下面的评论中所建议的,我们可以使用通用的参数 $SharePoint.Type.<GUID>.FullName$
,并将 <GUID> 替换为在 WebPart 声明中添加的 GUID。在示例中,代码如下:<WebPartPages:SPUserCodeWebPart
runat="server"
Description="ServiceWP"
Title="ServiceWP"
AssemblyFullName="$SharePoint.Project.AssemblyFullName$"
SolutionId="$SharePoint.Package.Id$"
ID="servicewp"
TypeFullName="$SharePoint.Type.a2548058-31d8-4364-8043-1ea3a1eb21e1.FullName$" >
</WebPartPages:SPUserCodeWebPart>
此外,在页面声明中,我们必须更改 MasterPage 的 URL,以引用自定义的母版页。
<%@ Page language="C#" MasterPageFile="~site/_catalogs/masterpage/WSMasterPage.master" ... %>
如果网站集不是 Web 应用程序的根目录(例如,http://dev/sites/wstest),则需要使用 ~site
参数。
创建页面后,我们必须创建一个功能来将其部署到 SharePoint 文档库。这可以通过模块实现,如下所示(在解决方案中,它位于 WSServicePage 文件夹中)。
<Module Name="WSServicePage">
<File Path="WSServicePage\WSServicePage.aspx" Url="Documents/WSServicePage.aspx" />
</Module>
使用 jQuery 调用 Web 服务
最后一步是创建一个调用服务的页面;这非常简单,有一个按钮可以调用我们的自定义 Web 服务,并在 div
面板(ID 为 #list
)中显示格式正确的响应。
为了简化开发,我们使用 jQuery 框架的 AJAX 功能,可以将脚本插入开箱即用的 SharePoint 内容编辑器 Web 部件,或直接将其添加到页面的源代码中。
$(function () {
$.getJSON("/Documents/WSServicePage.aspx", function(data) {
$.each(data.Sites, function(i,s) {
var txt = 'Site ' + s.Title + ' has ' + s.ListsCount + ' lists' ;
$('<li>').text(txt).appendTo($('#list'));
});
});
});
结论
在本文中,我们分析了一种克服 Office 365 限制的方法:沙盒解决方案有时可能会因为所有限制而难以使用,但是有许多新技术允许开发人员通过探索新方法和解决方案来处理这些问题。
这种方法无意取代其他有效且完全受支持的解决方案,例如 JavaScript 客户端对象模型 (JSOM)、SPServices,或对 SharePoint REST 服务的简单调用,相反,它只是建议一种重用使用服务器端对象模型开发的源代码的方法,或者适用于不熟悉 JavaScript 的用户。此外,当我们需要使用需要许多异步调用 JSOM 脚本的 SharePoint 上下文进行嵌套查询时,我认为这种方法非常有用。
关于源代码
解决方案中有四个功能:- WSWebpart:包含服务逻辑的 Web 部件。
- WSMasterPage:简单的母版页。
- WSService:包含 Web 部件的页面。
- WSConsumer:调用“服务”的页面。

历史
- 2012 年 2 月 10 日:初始版本。
- 2012 年 2 月 14 日:更新源代码。