WCF Data Services是SharePoint 2010中一个极具吸引力的新特性。然而,因为它的强大,直接对其进行编程仍然会有点痛苦。幸运的是,一个新的相关技术 —— ASP.Net AJAX模板 – 可以完美的与WCF Data Service进行集成,并允许我们快速构建优雅的,可维护的和反应迅速的AJAX应用程序。
在本文中,我将详细描述ASP.Net AJAX模板,并在Visual Studio 2010中一步一步的构建一个非常简单的应用程序页面。接着使用ASP.Net AJAX模板来显示SharePoint 2010中通过WCF Data Services发布的JSON格式的列表数据。
单纯从技术层面解释什么是ASP.Net AJAX模板可能并不容易。不妨先假设没有这项技术,看看传统方式是如何解决问题的。如果SharePoint传递给你一个JavaScript中的JSON对象的数组,现在的你会如何将其转换成HTML?
最常见的答案似乎就是JQuery的.append()语句了。代码大致如下:
for ( var i = 0 ; i < userStories.length; i ++ ) { $( " #userStories " ).append( " <div class='userStoryCard'> " + userStories[i].Title + " </div> " ); }这种类型的解决方案的问题,或者说任何没有使用模板引擎的解决方案,事实上都无法清楚的分离数据访问逻辑和界面展现。事实上,这种情形很像回到了经典的Active Server Pages风格,可维护性很差,代码一塌糊涂。随着我们不断的从SharePoint获取数据,整个代码会变得更加杂乱。
模板的目标是使你不必编写上面那样的代码,使用模板后的代码应该像下面这样::
< div class ="userStoryCard" > {{ Title }} </ div >整洁,漂亮。理想状态下模板应提供这样一个的解决方案:
最大限度地减少管道(plumbing)代码 清晰的分离数据访问逻辑和界面展示 简化存回服务器端的数据 并且没有ViewState!在进入模板学习前,让我们先来快速看一下如何在Visual Studio 2010中构建一个应用程序页面。这是我们将来编写代码的基础。当然你可以把所有代码都放在一个内容编辑器Web部件里,但是Visual Studio提供了更好的智能提示和调试的支持,因此我们选择在应用程序页中运行。
为了在Visual Studio 2010中建立一个简单的应用程序页面,先选择“新建项目”,然后导航到SharePoint 2010模板分类,选择“空白SharePoint项目”
点击确定后,Visual Studio会弹出SharePoint自定义向导:
该窗口要求你选择一个站点用于调试。当你按F5键(开始调试)时,Visual Studio 2010会进行wsp文件打包,然后将其部署到这里你填写的URL对应的站点上,同时附加上对应的w3wp进程,并打开一个浏览器显示该sharepoint站点。这样,你就立即拥有一个调试环境了。
如果你对这一过程印象不深刻,那么你可能没有做过多少WSS 3.0的开发——但请相信我,这个改进大大节省了我们的时间。尽管在本例中我们不会写任何服务器端代码,但仍旧可以体会到微软在SharePoint 2010上倾注了不少的心力。
当Visual Studio完成项目初始化后,选择项目->添加新项,然后选择应用程序页。
Visual Studio接下来会自动生成一个完全套用SharePoint母版页并包含内容控件的页面。
代码 <% @ Assembly Name = " $SharePoint.Project.AssemblyFullName$ " %> <% @ Import Namespace = " Microsoft.SharePoint.ApplicationPages " %> <% @ Register Tagprefix = " SharePoint " Namespace = " Microsoft.SharePoint.WebControls " Assembly = " Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c " %> <% @ Register Tagprefix = " Utilities " Namespace = " Microsoft.SharePoint.Utilities " Assembly = " Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c " %> <% @ Register Tagprefix = " asp " Namespace = " System.Web.UI " Assembly = " System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 " %> <% @ Import Namespace = " Microsoft.SharePoint " %> <% @ Assembly Name = " Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c " %> <% @ Page Language = " C# " AutoEventWireup = " true " CodeBehind = " UserStories.aspx.cs " Inherits = " PreDemo.Layouts.PreDemo.UserStories " DynamicMasterPageFile = " ~masterurl/default.master " %> < asp:Content ID ="PageHead" ContentPlaceHolderID ="PlaceHolderAdditionalPageHead" runat ="server" > </ asp:Content > < asp:Content ID ="Main" ContentPlaceHolderID ="PlaceHolderMain" runat ="server" > Hello World! </ asp:Content > < asp:Content ID ="PageTitle" ContentPlaceHolderID ="PlaceHolderPageTitle" runat ="server" > 应用程序页 </ asp:Content > < asp:Content ID ="PageTitleInTitleArea" ContentPlaceHolderID ="PlaceHolderPageTitleInTitleArea" runat ="server" > 我的应用程序页 </ asp:Content >(“Hello World!”是我写的)。现在如果你按F5键或者点击生成->部署解决方案,则Visual Studio会打包该应用程序页到一个wsp文件并将其部署到SharePoint。如果你导航到该应用程序页的话(例如本例中为http://contoso14/_layouts/PreDemo/UserStories.aspx)则会看到如下的显示:
很震撼吧!你真的应该如此。我们没有编写冗长的,重复的代码,或者容易出错的CAML,没有运行任何DOS(或PowerShell)脚本,没有手工部署到GAC,甚至没有注意到后台自动生成的Feature.xml文件,然而,我们已经部署完了。
ASP.Net AJAX模板的安装比较棘手。为了得到它你需要先在CodePlex上下载最新推出的AJAX控件工具包源代码(本例中下载下来的是AjaxControlToolkit-9c860ac12ae9.zip)。并在Visual Studio(它的项目中包含了Visual Studio 2008和2010两个版本)中编译(编译时还需要安装Microsoft Ajax Minifier 2.0)然后将Javascript文件复制到SharePoint的layouts目录下。需要复制的目录有:
从 AjaxControlToolkit.Source\SampleWebSites\AjaxClientWebSite\Scripts; 复制到
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ \14\TEMPLATE\LAYOUTS\Scripts
还有从 AjaxControlToolkit.Source\Client\MicrosoftAjax\Templates; 复制到
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ \14\TEMPLATE\LAYOUTS\Scripts
或者采用更符合标准的做法,将其复制到Visual Studio项目的layouts目录中。
Javascript文件都就位后,我们就可以编写最简单的模板页代码了:
<% @ Assembly Name = " $SharePoint.Project.AssemblyFullName$ " %> <% @ Import Namespace = " Microsoft.SharePoint.ApplicationPages " %> <% @ Register Tagprefix = " SharePoint " Namespace = " Microsoft.SharePoint.WebControls " Assembly = " Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c " %> <% @ Register Tagprefix = " Utilities " Namespace = " Microsoft.SharePoint.Utilities " Assembly = " Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c " %> <% @ Register Tagprefix = " asp " Namespace = " System.Web.UI " Assembly = " System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 " %> <% @ Import Namespace = " Microsoft.SharePoint " %> <% @ Assembly Name = " Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c " %> <% @ Page Language = " C# " AutoEventWireup = " true " CodeBehind = " UserStories.aspx.cs " Inherits = " PreDemo.Layouts.PreDemo.UserStories " DynamicMasterPageFile = " ~masterurl/default.master " %> < asp:Content ID ="PageHead" ContentPlaceHolderID ="PlaceHolderAdditionalPageHead" runat ="server" > < style type ="text/css" > .sys-template { display : none ; } </ style > < script src ="/_layouts/Scripts/MicrosoftAjax/Start.js" type ="text/javascript" ></ script > < script src = "/_layouts/Scripts/MicrosoftAjax/MicrosoftAjax.js" type ="text/javascript" ></ script > < script type ="text/javascript" > Sys.require([ Sys.components.dataView, Sys.components.openDataServiceProxy, Sys.scripts.jQuery ]); Sys.onReady( function () { var dataSource = Sys.create.openDataServiceProxy( ' /_vti_bin/ListData.svc ' ); Sys.query( " #userStoriesList " ).dataView({ dataProvider: dataSource, fetchOperation: " UserStories " , feachParameters: { orderby: ' 标题 ' }, autoFetch: " true " }); }); </ script > </ asp:Content > < asp:Content ID ="Main" ContentPlaceHolderID ="PlaceHolderMain" runat ="server" > Hello World! < ul id ="userStoriesList" class ="sys-template" > < li > {{ 标题 }} </ li > </ ul > </ asp:Content > < asp:Content ID ="PageTitle" ContentPlaceHolderID ="PlaceHolderPageTitle" runat ="server" > 应用程序页 </ asp:Content > < asp:Content ID ="PageTitleInTitleArea" ContentPlaceHolderID ="PlaceHolderPageTitleInTitleArea" runat ="server" > 我的应用程序页 </ asp:Content >其中的UserStories是我的一个任务列表。我事先填充了一些示例数据。
跳过JavaScript部分,我们先来看Main content一节中名为userStoriesList的<ul>无序列表。 其中的<li>元素包围着一个有趣的符号:{{ 标题 }}。这样就声明了一个绑定到SharePoint中ListItem的标题字段。我们也可以改成任何其他的列,如“优先级”,或者在其中添加JavaScript,如{{ String.format("{0:yyyy-M-dd}", 修改时间) }}。
注意PageHead的脚本引用。引用MicrosoftAjax.js使得我们可以使用ASP.Net AJAX的核心功能。Start.js使得我们可以使用Sys.require功能,以便导入其他具有依赖关系的Javascript。
至此,我们还没有导入足够的JavaScript以提供我们需要的模板功能。这部分工作由Sys.require来完成。声明了1.DataView对象,用于完成主要的模板工作;2.openDataServiceProxy,知道如何与SharePoint的ADO.Net Data Service进行通讯;3. jQuery。如果你用Firebug看的话就会发现Sys.require加载了哪些额外的.js文件,就像MicrosoftAjaxTemplates.js。而且是按照正确的顺序加载到页面上的。这种方式保证了页面不会放上很多不需要的Javascript。
真正的奇迹发生在Sys.onReady里,其功能是在DOM加载完成后执行一次。首先它实例化了一个openDataServiceProxy对象,负责与一个oData端点进行通讯,在我们的例子中是一个ADO.Net Data Services。
它做的第二件事情是实例化一个DataView对象,并将其关联到userStoriesList元素。fetchOperation参数告诉它从哪个列表获取ListItems(本例中为UserStories列表)。fetchParameters参数告诉它如何对数据进行排序,筛选或分页。
DataView实例化后(由于autoFetch被设为true) 会通过其dataProvider检索JSON数据,并为每个返回的行重复所关联的DOM元素的innerHTML,而且以实际的数据代替绑定语法。看起来似乎很简单,但在将来的博文中你会看到它很快会变得很复杂。
最后一个要注意的是sys-template类。这是一个在ASP.Net AJAX中预定义的CSS类,当完成渲染工作后,由ASP.Net AJAX将其设置为display:block。因此,我们需要为sys-template创建一个CSS类并设为display:none,这样在页面加载过程中最终用户就看不到你的模板代码了。
现在,如果你点击生成->部署解决方案,就会看到如下的显示:
当然,可能如果用服务器端代码编写这个功能的话实现起来更容易。这个话题先搁在这儿,我们的解决方案还有很多潜力可挖。例如,从哪个层面上与jQuery结合,可以使界面更美观?如何将数据写回到上下文服务器端?如何实现主-子关系?我们将在随后的博文中一起来探讨这些问题。
参考资料
Client Side AJAX Applications in SharePoint 2010-Part3:ASP.Net AJAX Templating 101
ASP.NET AJAX: Client Postbacks cause a Sys.ArgumentTypeException
转载于:https://www.cnblogs.com/Sunmoonfire/archive/2010/07/22/1781936.html
相关资源:数据结构—成绩单生成器