用Silverlight调用SharePoint User Profile Web Service

调用SharePoint Web Service本来就不是一件令人愉悦的事情,如果期间在遇到一些诡异的问题的话……譬如我今天遇到的这件 ……

按照惯例,添加好引用,编写代码调用GetUserProfileByNameAsync方法,稍等一下,一个异常抛出了(liao),大概反序列化某个属性时发生了错误。

而这个错误竟然是因为Visual Studio生成的Reference.cs文件和SharePoint提供的WSDL文件映射错误引起的,解决方法就是手工更改Reference.cs文件,该文件的路径是:项目文件夹\Service References\引用名称\Reference.cs。

打开后定位到PropertyData类,我们需要给以下5个属性重新排序,顺序如下:

  1. IsPrivacyChanged
  2. IsValueChanged
  3. Values
  4. Name
  5. Privacy
重新排序的方法就是找到这几个属性,修改它们各自的System.Runtime.Serialization.DataMemberAttribute,修改或增加参数Order,如:
[System.Runtime.Serialization.DataMemberAttribute(IsRequired = true, Order = 1)]
public bool IsPrivacyChanged { ... }

这一步完成之后,调用GetUserProfileByNameAsync方法不会再抛出异常了,但是拿到的结果中,所有的PropertyData.Values都为null,但其实SharePoint Server已经返回了结果,但这些结果并没有被正确的反序列化出来,好在我们还有办法直接去解析原始的XML结果。
我们首先需要实现一个IEndpointBehavior和IClientMessageInspector:
public class UserProfilesBehavior : IEndpointBehavior
{
public UserProfilesInspector Inspector { get; private set; }

public UserProfilesBehavior()
{
this.Inspector = new UserProfilesInspector();
}

public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{ }

public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(Inspector);
}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{ }

public void Validate(ServiceEndpoint endpoint)
{ }

}
public class UserProfilesInspector : IClientMessageInspector
{
public string Account { get; private set; }

XNamespace xmlns = "http://microsoft.com/webservices/SharePointPortalServer/UserProfileService";

public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//像这样取出需要的内容
XDocument document = XDocument.Load(new System.IO.StringReader(reply.ToString()));
this.Account = this.GetValue(document, "AccountName").ToString();
}

private object GetValue(XDocument document, string propertyName)
{
var node = document.Descendants().FirstOrDefault((element) => { return element.Name == xmlns + "PropertyData" && element.Element(xmlns + "Name").Value == propertyName; });
if (node != null)
{
var valueNode = node.Descendants(xmlns + "Value").FirstOrDefault();
if (valueNode != null)
{
return valueNode.Value.Replace("_MThumb","_LThumb");
}
}
return string.Empty;
}

public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
return null;
}

}

然后更改一下调用Web Service的代码,把刚才写的UserProfilesBehavior以Behavior和UserState的形式进去:

UserProfilesBehavior behavior = new UserProfilesBehavior();
SPUserProfile.UserProfileServiceSoapClient userSoap = new SPUserProfile.UserProfileServiceSoapClient(binding, endpoint);
userSoap.Endpoint.Behaviors.Add(behavior);//添加为Behavior
userSoap.GetUserProfileByNameCompleted += new EventHandler<SPUserProfile.GetUserProfileByNameCompletedEventArgs>(userSoap_GetUserProfileByNameCompleted);
userSoap.GetUserProfileByNameAsync(people.Account, behavior);//添加为UserState

那么在GetUserProfileByNameAsync完成时的事件处理程序中,就可以通过UserState——也就是刚才编写的UserProfilesBehavior来拿到需要的数据了:

void userSoap_GetUserProfileByNameCompleted(object sender, SPUserProfile.GetUserProfileByNameCompletedEventArgs e)
{
if (e.Error == null)
{
UserProfilesBehavior behavior = (UserProfilesBehavior)e.UserState;
string account = behavior.Inspector.Account;
}
}

参考资源:http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/d1c6a143-dc1b-4788-8431-e16f0269f8b4/

发表评论

电子邮件地址不会被公开。 必填项已用*标注