由于Silverlight要访问SharePoint里List的数据,所以需要在Silverlight里调用SharePoint的相应的WebService。
一开始我在VS.net2008里Silverlight工程下添加“Service Reference”时,总是出现“Object reference not set to an instance of an object”这样的错误,添加不了WebService引用,后来查找相关资料,解决了这个问题:
若你也遇到了同样的情况,请先去‘添加/删除软件’里看下Silverlight 2 Beta 2 Tools的安装体积,正常的是1.18M,如果你的是1.4M,那么极有可能是安装问题。有可能你安装了去年12月发布的Blend等软件。
在Silverlight.net论坛找到一种可行的解决办法:
1):确定所有与Silverlight相关的应用程序都被卸载
2):删除以下DLL:C:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE/Microsoft.VisualStudio.ServicesProxy.dll
以上步骤全部完成后,安装Silverlight 2 Beta 2。
成功添加WebService后,尝试用WebService调用SharePoint里的List信息:
- BasicHttpBinding bind = new BasicHttpBinding();
- EndpointAddress endpoint = new EndpointAddress( http://localhost/_vti_bin/Lists.asmx);
- SPListService.ListsSoapClient lsc = new MenuControlForSharePoint.SPListService.ListsSoapClient(bind, endpoint);
- lsc.GetListItemsCompleted += new EventHandler<MenuControlForSharePoint.SPListService.GetListItemsCompletedEventArgs>(lsc_GetListItemsCompleted);
- XElement viewFileds = new XElement("ViewFields",
- new XElement("FieldRef", new XAttribute("Name", "Title")),
- new XElement("FieldRef", new XAttribute("Name", "Hyperlink")),
- new XElement("FieldRef", new XAttribute("Name", "TopLevelLink")),
- new XElement("FieldRef", new XAttribute("Name", "ParentLink"))
- );
- lsc.GetListItemsAsync("MenuList", null, null, viewFileds, null, null, null);
但运行时总是报错“The remote server returned an unexpected response: (404) Not Found.”。通过找资料,怀疑可能是跨域访问的问题,于是将'clientaccesspolicy.xml'文件放在SharePoint中对应站点的域根目录下,该xml文件内容为:
- <?xml version="1.0" encoding="utf-8"?>
- <access-policy>
- <cross-domain-access>
- <policy>
- <allow-from http-request-headers="*">
- <domain uri="*"/>
- </allow-from>
- <grant-to>
- <resource path="/" include-subpaths="true"/>
- </grant-to>
- </policy>
- </cross-domain-access>
- </access-policy>
但是错误仍然存在,且多方查找资料无果。
为了查找错误根源所在,我在.net下创建了一个B/S的项目,并在该项目中添加WebService来访问SharePoint的Lists.asmx:
- localhost.Lists ls = new SharePoint.localhost.Lists();
- ls.Url = "http://localhost/_vti_bin/Lists.asmx";
- XmlDocument xmlDoc = new System.Xml.XmlDocument();
- XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
- XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
- XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
- ndQueryOptions.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>" + "<DateInUtc>TRUE</DateInUtc>";
- ndViewFields.InnerXml = "<FieldRef Name='Title' />";
- ndQuery.InnerXml = "<Where><And><Gt><FieldRef Name='Field1'/>" +
- "<Value Type='Number'>5000</Value></Gt><Gt><FieldRef Name='Field2'/>" +
- "<Value Type='DateTime'>2003-07-03T00:00:00</Value></Gt></And></Where>";
- XmlNode ndListItems =ls.GetListItems("MenuList", null, null,ndViewFields, null, ndQueryOptions, null);
运行时报错“请求因 HTTP 状态 401 失败: Unauthorized。”。估计是没有访问WebService的权限,在调用WebService之前做如下设置则可解决该问题:
- ls.Credentials = new System.Net.NetworkCredential("username","password","domain");
- 或者
- ls.UseDefaultCredentials = true;
- 或者:
- ls.Credentials = System.Net.CredentialCache.DefaultCredentials;
但是运行时抛出另外一个异常:“Exception of type 'Microsoft.SharePoint.SoapServer.SoapServerException' was thrown.”
后来通过查找,发现我犯了一个很大的错误。我的SharePoint站点地址为http://localhost ,但在该站点下有一个字站点Document Center ( http://localhost/docs ),我的MenuList list是建立在Document Center下的,所以WebService地址应该是http://localhost/Docs/_vti_bin/Lists.asmx,而不应该是http://localhost/_vti_bin/Lists.asmx。
在Silverlight工程中修改这个错误后,运行能够成功调用WebService并返回一个XML文本:
- <listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
- <rs:data ItemCount="11">
- <z:row ows_Title="Menu1" ows_Hyperlink="http://www.baidu.com, http://www.baidu.com" ows_TopLevelLink="1" ows_MetaInfo="1;#" ows__ModerationStatus="0" ows__Level="1" ows_ID="1" ows_owshiddenversion="1" ows_UniqueId="1;#{E937FAC3-5018-4BF3-B05F-7331C94532A8}" ows_FSObjType="1;#0" ows_Created="2008-08-28 17:16:56" ows_FileRef="1;#Docs/Lists/MenuList/1_.000" />
- <z:row ows_Title="Menu2" ows_Hyperlink="http://www.sina.com.cn, http://www.sina.com.cn" ows_TopLevelLink="1" ows_MetaInfo="2;#" ows__ModerationStatus="0" ows__Level="1" ows_ID="2" ows_owshiddenversion="1" ows_UniqueId="2;#{161B5EF0-B3ED-4BF6-984C-F59ECA89E761}" ows_FSObjType="2;#0" ows_Created="2008-08-28 17:17:10" ows_FileRef="2;#Docs/Lists/MenuList/2_.000" />
- <z:row ows_Title="Menu2:Child1" ows_TopLevelLink="0" ows_ParentLink="Menu2" ows_MetaInfo="3;#" ows__ModerationStatus="0" ows__Level="1" ows_ID="3" ows_owshiddenversion="1" ows_UniqueId="3;#{170D7079-A012-4B4D-B64F-DAE701F1B864}" ows_FSObjType="3;#0" ows_Created="2008-08-28 17:17:24" ows_FileRef="3;#Docs/Lists/MenuList/3_.000" />
- </rs:data>
- </listitems>
我试图用Linq来查询这些XML数据:doc.Descendants("z:row"),但结果为null或者报错。后来发现应该将前缀替换一下
doc.Descendants("{#RowsetSchema}row"), 这样可以正确运行,但我还不知道这是不是标准的写法。
最后完整的解析代码如下:
- void lsc_GetListItemsCompleted(object sender, MenuControlForSharePoint.SPListService.GetListItemsCompletedEventArgs e)
- {
- XDocument doc = XDocument.Parse(e.Result.ToString());
- var lstMenuInfo = from menuInfo in doc.Descendants("{#RowsetSchema}row").ToList()
- select new MenuInfo
- {
- Title = (string)menuInfo.Attribute("ows_Title"),
- Hyperlink = (string)menuInfo.Attribute("ows_Hyperlink"),
- TopLevelLink = (int)menuInfo.Attribute("ows_TopLevelLink") == 1,
- ParentLink = (string)menuInfo.Attribute("ows_ParentLink"),
- };
- // Init menu
- InitMenu(lstMenuInfo);
- //create menu
- menu.Render();
- //exapand all menu items
- menu.ExpandAll();
- }
另外,附带一段Mical给我邮简里的一个示例代码:
- // get the blog and photo links
- XNamespace msn = http://schemas.microsoft.com/msn/spaces/2005/rss;
- XElement elem = XElement.Load(reader);
- var query = from item in elem.Descendants("item")
- where (string)item.Element(msn + "type").Value == "blogentry"