All I wanted to do was get hold of a users' email address and preferred name from the profile database. I needed to get it from my web service so that I could go ahead and add the user to a custom group.
So I put some code together:
ServerContext ctx = null;
UserProfileManager userProfileManager = null;
UserProfile user = null;string[] ret = new string[3];
try
{
ctx = ServerContext.GetContext(new SPSite(sTopSite));
userProfileManager = new UserProfileManager(ctx);
user = null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
if (!userProfileManager.UserExists(sAccountName))
user = userProfileManager.CreateUserProfile(sAccountName);
else
user = userProfileManager.GetUserProfile(sAccountName);
});…
But it kept telling me I didn't have the necessary privileges, or the context of the site was invalid, or there was an error in native code (on the top of the call stack) or, or, or….
I've searched quite a bit and have tried a number of approaches including impersonating the administrator, changing the app pool identity for the web service to admin, fixing the impersonation details in the web.config…
Whatever I try though I get an error, usually something like:
"Operation is not valid due to the current state of the object."
Stack trace:
at Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context)
at Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(HttpContext context)
at Microsoft.Office.Server.UserProfiles.UserProfileGlobal.GetCurrentUserName()
at Microsoft.Office.Server.UserProfiles.UserProfileManager.get_strCurrentAccountName()
at Microsoft.Office.Server.UserProfiles.UserProfileManager.UserExists(String strAccountName)
at HP.WebServices.CreateWorkspace.SPUtils.<>c__DisplayClass2.<getUser>b__0() in c:Documents and Settings…….HP.WebServices.CreateWorkSpaceApp_CodeSPUtils.cs:line 66
at Microsoft.SharePoint.SPSecurity.CodeToRunElevatedWrapper(Object state)
at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.<RunWithElevatedPrivileges>b__2()
at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
In fact the only way I've been able to get this working is by using the SharePoint web services but really that's not something I wanted to do, I wanted to call the object model direct. Why? Well for one, the creation of a site collection takes time and the last thing I wanted to do was introduce more delays while my code calls out to another web service.
Here is how I got around the problem (UsersWS is the web reference I added to http://[mysite]/_vti_bin/UserGroup.asmx):
UsersWS.UserGroup userWS = new UsersWS.UserGroup();
Uri uri = new Uri(sURL + "/_vti_bin/UserGroup.asmx");
userWS.Url = uri.AbsoluteUri;
userWS.Credentials = new System.Net.NetworkCredential("Administrator", "", "HP");;
userWS.AddUserToGroup(sGroup, sUserDetails[2], sUserDetails[0], sUserDetails[1], "Added through web service");
I hope this
a) Helps anyone else going through similar issues
b) Brings any known solutions out of the woodwork!
Oh, and in case it's useful the following shows how to create a group, associate it with a permissions type and add it to the quick launch:
web.SiteGroups.Add(sGroup, web.SiteAdministrators[0], null, "Automatically created site group for " + sGroup);
spGroup = web.SiteGroups[sGroup];
spGroup.AllowRequestToJoinLeave = true;
web.Properties[sVTI_GroupID] = spGroup.ID.ToString();
web.Properties.Update();
web.Properties["vti_associategroups"] = web.Properties["vti_associategroups"] + ";" + spGroup.ID.ToString();
web.Properties.Update();
web.Update();
int iGroupID = int.Parse(web.Properties[sVTI_GroupID]);
SPRoleAssignment spRoleAssignment = new SPRoleAssignment(spGroup);
SPRoleDefinition role = web.RoleDefinitions[sGroupRoleDefinition];
spRoleAssignment.RoleDefinitionBindings.Add(role);
web.RoleAssignments.Add(spRoleAssignment);
web.Update();