I had the need the other day for a way of displaying a list of site users on an InfoPath form that the user can select from and came across this article on Jan Tielens' blog which I thought would do the trick. Unfortunately it was for SharePoint 2003 rather than 2007 so I had to play around a bit to get it working, & came up with 2 methods of accompishing it which I wanted to share with you.
Create a New Visual Studio .Net project based on the InfoPath Form Template and call it ExampleGetSiteUsers.
The first thing you'll need to do is go into Tools -> Form Options and set the forms security level to Full Trust

Then create your main data source like so

We'll need to create a DataConnection to the GetUserCollectionFromSite Method of the UserGroup SharePoint webservice.
From the Visual Studio menu select Data -> Data Connections
Click Add

Select Create a new connection to Receive data then click Next

Select Web service then click Next

Enter http://YourServerName/_vti_bin/UserGroup.asmx for the webservice location making sure you put in your moss servers name then click next

Select the GetUserCollectionFromSite method then click Next

Click Next
Enter a meaningful name for the data connection & ensure "Automatically retrieve data when the form is opened" is ticked. Then click Finish & close the data connections window. We now need to add a second data connection that will use the following XML file as it's source. Copy the code below to a new file & name it SiteUsersAndGroups.xml save it to a location on your machine that you'll remember.
<?xml version="1.0" encoding="utf-8" ?>
<SiteUsersAndGroups>
<Users xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
<User ID="" Sid="" Name="" LoginName="" Email="" Notes="" IsSiteAdmin="" IsDomainGroup=""/>
<User ID="" Sid="" Name="" LoginName="" Email="" Notes="" IsSiteAdmin="" IsDomainGroup=""/>
</Users>
</SiteUsersAndGroups>
. . .
From the Visual Studio menu select Data -> Data Connections Add a new connection to Receive data
This time select XML Document as the source then click Next
Enter the location of the XML document we just created then click Next
Click Next
Click Finish & close the Data Connections window
Create a couple of DropDown Lists on your Form for the 2 fields in the main data source
Go into the properties of the first Drop Down that is bound to our method1 field
Select "Look up values from an external data source" & set the Data source to the connection we just created Click on the Select XPath for the entries
Select the User repeating group & click OK
Set the value to the ID and the Display name to the Name We now need to create yet another Data connection that we can use as the source for our second Drop Down. Normally you wouldn't need to do this as you could use the same source for both, but because I'm showing 2 methods which will be slightly different in the content they show we'll need a second connection. Follow exactly the same steps as we used to create the first data connection to an xml file, but name the connection SiteUsers as in the second method we'll be stripping out groups.
Now we'll go into the properties of the second Drop Down & bind it to this new connection like so
You'll now need to create a new class within your project called Users.cs which contains the following code
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:2.0.50727.42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
using System.Xml.Serialization;
//
// This source code was auto-generated by xsd, Version=2.0.50727.42.
//
/// [System.CodeDom.Compiler.
GeneratedCodeAttribute(
"xsd",
"2.0.50727.42")]
[System.
SerializableAttribute()]
[System.Diagnostics.
DebuggerStepThroughAttribute()]
[System.ComponentModel.
DesignerCategoryAttribute(
"code")]
[System.Xml.Serialization.
XmlTypeAttribute(AnonymousType =
true)]
[System.Xml.Serialization.
XmlRootAttribute(Namespace =
"http://schemas.microsoft.com/sharepoint/soap/directory/", IsNullable =
false)]
public partial class Users{
private User[] itemsField;
/// [System.Xml.Serialization.
XmlElementAttribute(
"User")]
public User[] Items
{
get {
return this.itemsField;
}
set {
this.itemsField =
value;
}
}
}
/// [System.CodeDom.Compiler.
GeneratedCodeAttribute(
"xsd",
"2.0.50727.42")]
[System.
SerializableAttribute()]
[System.Diagnostics.
DebuggerStepThroughAttribute()]
[System.ComponentModel.
DesignerCategoryAttribute(
"code")]
[System.Xml.Serialization.
XmlTypeAttribute(AnonymousType =
true)]
public partial class User{
private string idField;
private string sidField;
private string nameField;
private string loginNameField;
private string emailField;
private string notesField;
private string isSiteAdminField;
private string isDomainGroupField;
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string ID
{
get {
return this.idField;
}
set {
this.idField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string Sid
{
get {
return this.sidField;
}
set {
this.sidField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string Name
{
get {
return this.nameField;
}
set {
this.nameField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string LoginName
{
get {
return this.loginNameField;
}
set {
this.loginNameField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string Email
{
get {
return this.emailField;
}
set {
this.emailField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string Notes
{
get {
return this.notesField;
}
set {
this.notesField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string IsSiteAdmin
{
get {
return this.isSiteAdminField;
}
set {
this.isSiteAdminField =
value;
}
}
/// [System.Xml.Serialization.
XmlAttributeAttribute()]
public string IsDomainGroup
{
get {
return this.isDomainGroupField;
}
set {
this.isDomainGroupField =
value;
}
}
}
. . .
Finally we're ready to write some code in the FormCode file Here's some I cooked up earlier which I've heavily commented so you can see what I'm doing.
using Microsoft.Office.InfoPath;
using System;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Serialization;
namespace ExampleGetSiteUsers
{
public partial class FormCode
{
// NOTE: The following procedure is required by Microsoft Office InfoPath.
// It can be modified using Microsoft Office InfoPath.
public void InternalStartup()
{
this.EventManager.FormEvents.Loading += new LoadingEventHandler(FormEvents_Loading);
}
void FormEvents_Loading(object sender, LoadingEventArgs e)
{
//get an XPathNavigator to our webservice method
XPathNavigator siteUsers = this.DataSources["GetUserCollectionFromSite"].CreateNavigator();
//create the XmlNamespaceManager that will allow us to navigate the xml
XmlNamespaceManager umanager = new XmlNamespaceManager(siteUsers.NameTable);
umanager.AddNamespace("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
umanager.AddNamespace("tns", "http://schemas.microsoft.com/sharepoint/soap/directory/");
//get the node that contains all the users from the call to the web service
XPathNavigator allusers = siteUsers.SelectSingleNode("/dfs:myFields/dfs:dataFields/tns:GetUserCollectionFromSiteResponse/tns:GetUserCollectionFromSiteResult/tns:GetUserCollectionFromSite/tns:Users", umanager);
//method 1
//get an XPathNavigator to our data source used by the first Drop Down
XPathNavigator siteUsersAndGroups = this.DataSources["SiteUsersAndGroups"].CreateNavigator();
//create the XmlNamespaceManager that will allow us to navigate the xml
//we can reuse this for our second data source in method 2 as the xml schema is identical
XmlNamespaceManager dmanager = new XmlNamespaceManager(siteUsersAndGroups.NameTable);
dmanager.AddNamespace("tns", "http://schemas.microsoft.com/sharepoint/soap/directory/");
//get the node within this data source that represents users
XPathNavigator dusers = siteUsersAndGroups.SelectSingleNode("/SiteUsersAndGroups/tns:Users", dmanager);
//fill this data source with the users returned by the web service call
dusers.ReplaceSelf(allusers);
//method 2
//We'll start off by deserializing the xml node of users we got from the web service call
//into our users class to make workingwith the data easier.
Users su;
XmlSerializer serializer = new XmlSerializer(typeof(Users));
su = (Users)serializer.Deserialize(allusers.ReadSubtree());
//create an XPathNavigator to the second data source we created from the xml document
//i.e. the data source we're using for the second Drop Down
//specifically the first User node
XPathNavigator siteUser = this.DataSources["SiteUsers"].CreateNavigator().SelectSingleNode("/SiteUsersAndGroups/tns:Users/tns:User", dmanager);
//create a clone of the this node so we can change the values
XPathNavigator currentNode = siteUser.Clone();
//We'll need to iterate through the users in our User class in
//reverse order otherwise they'll appear in our drop down in decending order
for (int i = su.Items.Length - 1; i >= 0; i--)
{
User user = su.Items[i];
//Check each user to see if it's actually a group as we don't want those
if (user.IsDomainGroup == "False")
{
XPathNavigator newNode = currentNode;
//change some of the value on the clone, I'm only changing the 2 we need for this example
//but you could change them all
newNode.SelectSingleNode("/SiteUsersAndGroups/tns:Users/tns:User/@ID", dmanager).SetValue(user.ID);
newNode.SelectSingleNode("/SiteUsersAndGroups/tns:Users/tns:User/@Name", dmanager).SetValue(user.Name);
try
{
//insert the new node after the current one
currentNode.InsertAfter(newNode);
}
catch (Exception)
{
}
currentNode = newNode.Clone();
}
}
//this is the first blank node from our sample xml file so we need to get rid of it
siteUser.DeleteSelf();
}
}
}
. . .
Go ahead & run the project. The first drop down will show all users & groups for your site, whilst the second will only show the users. You'll notice that the second Drop Down will be at a blank record at the end of the list of users & may be wondering why. The reason is that in our xml file that we used for the data connection there were 2 blank user nodes, which we need to have originally to tell InfoPath that User is a repeating group. Now that the connection is created we can edit the file that is stored within our project to get rid of the second blank record which will fix this up. To be able to edit the file you'll need to make sure that you haven't got manifest.xsf open otherwise you wont be able to open the file. From the solution window open SiteUsers & delete the second User node, save the file & rerun the project & voila...