Double Postback issue with Membership Request Web Part

Topics: Internet/Extranet Edition
Dec 18, 2007 at 4:09 PM
I have the web part working on my development server, but when I add it to a page in my production environment and try to submit a request it does a double postback and obviously validation fails the second time around because the user already exists. The thing is that I can't for the life of me figure out what the difference is between the two sites. In fact, they both came from the same imported cab file using a restore of the same Membership DB. The server is 64-bit whereas my VPC is 32-bit. Has anyone run into this before or have any idea where I should start? I've gone through as many configuration settings in central admin and the site specific settings as I can think of to compare the two, but I must be missing something...
Dec 18, 2007 at 5:53 PM
Update, I don't think it's doing a double postback. I walked through it in debug and it is running through the user creation (I modified the code to auto create the user in both the membership db and sharepoint site), then it changes the view to the complete step. Then somewhere between leaving the OnCreatingUser event and the rendering the view gets changed back to the default view and then it shows the validation issues (obviously).
Dec 18, 2007 at 7:54 PM
Alright, I have it solved. Since I modified the code to go ahead and create the whole account and everything and was calling it from within the OnCreatingUser event it didn't like it for some reason. So, I changed it back to just creating the list item in the OnCreatingUser event and overrode the OnCreatedUser event to then go ahead and create the SharePoint account and to setup membership etc. This seems to have fixed my issue.
Dec 19, 2007 at 8:53 PM
Hi,

I'm stumbling across the same problem. Think you could post some code on the forum to show all of us how you fixed it?

TIA!

Sig


cprimetrpt wrote:
Alright, I have it solved. Since I modified the code to go ahead and create the whole account and everything and was calling it from within the OnCreatingUser event it didn't like it for some reason. So, I changed it back to just creating the list item in the OnCreatingUser event and overrode the OnCreatedUser event to then go ahead and create the SharePoint account and to setup membership etc. This seems to have fixed my issue.

Dec 19, 2007 at 9:13 PM
Edited Dec 19, 2007 at 9:15 PM
Here you go:

MembershipRequest class

public static void ApproveMembership(MembershipRequest request, SPWeb web)
{
Hashtable xsltValues;
MembershipCreateStatus createStatus;
string tempPassword = string.Empty;

try
{
#region Validation
if (string.IsNullOrEmpty(request.UserName))
{
throw new Exception("User name must not be null or empty.");
}

if (string.IsNullOrEmpty(request.PasswordQuestion))
{
throw new Exception("You must specify a password question.");
}

if (string.IsNullOrEmpty(request.PasswordAnswer))
{
throw new Exception("You must specify a password answer.");
}

if (string.IsNullOrEmpty(request.UserEmail))
{
throw new Exception("Email address must not be null or empty.");
}
#endregion

#region Create Account in Membership DB

MembershipUser existingUser = Membership.GetUser(request.UserName);
if (existingUser != null)
{
Membership.DeleteUser(request.UserName, true);
}
tempPassword = Membership.GeneratePassword(Membership.MinRequiredPasswordLength, Membership.MinRequiredNonAlphanumericCharacters);
Membership.CreateUser(request.UserName, tempPassword, request.UserEmail, request.PasswordQuestion, request.PasswordAnswer, true, out createStatus);

#endregion

if (createStatus == MembershipCreateStatus.Success)
{
#region Create SharePoint User and Group Settings

//Add Membership User to SharePoint Collection and Groups
web.SiteUsers.Add(Membership.Provider.Name + ":" + request.UserName, request.UserEmail, request.FirstName + " " + request.LastName, "");
SharePointGroupMembership groupMembership = new SharePointGroupMembership(request.UserName);
groupMembership.UpdateUserGroupMembership(groupMembership, web);

#endregion

#region Send Confirmation Email with Temp Password

xsltValues = new Hashtable(1);
request.Password = tempPassword;
xsltValues.Add("cks:MembershipRequest", request);

Email.SendEmail(web, request.UserEmail, string.Format("{0}/_layouts/FBA/emails/MembershipApproved.xslt", web.Url), xsltValues);

#endregion
}
else
{
throw new Exception("Error creating user: " + createStatus);
}
}
catch (Exception ex)
{
TraceProvider.WriteTrace(0, TraceProvider.TraceSeverity.Exception, new Guid(), "FormsBasedAuthentication", "CKSIEE", "CKSIEE", ex.Message);
}
}


/// <summary>
/// used to bypass the manual approval process
/// </summary>
/// <param name="request">the current request</param>
public static void AutoApproveMembership(MembershipRequest request)
{
SPList reviewList;
SPWeb web = null;
SPSite site = null;

try
{

SPSecurity.RunWithElevatedPrivileges(delegate()
{
site = new SPSite(request.SiteURL);
web = site.OpenWeb();
if (web != null)
{

site.AllowUnsafeUpdates = true;
web.AllowUnsafeUpdates = true;
reviewList = web.ListsMembershipList.MEMBERSHIPREVIEWLIST;
if (reviewList != null)
{
foreach (SPListItem reviewItem in reviewList.Items)
{
if (reviewItemMembershipReviewListFields.USERNAME.ToString() == request.UserName)
{
reviewItemMembershipReviewListFields.STATUS = MembershipStatus.Approved;
reviewItem.Update();
reviewList.Update();
break;
}
}

}
else
{
TraceProvider.WriteTrace(0, TraceProvider.TraceSeverity.CriticalEvent, Guid.NewGuid(), Assembly.GetExecutingAssembly().FullName, "CKS.FormsBasedAuthentication", "MembershipRequest", "Unable to find Membership Review List");
}
}
});
}
catch (Exception ex)
{
TraceProvider.WriteTrace(0, TraceProvider.TraceSeverity.CriticalEvent, Guid.NewGuid(), Assembly.GetExecutingAssembly().FullName, "CKS.FormsBasedAuthentication", "MembershipRequest", ex.Message);
}
finally
{
if (web != null)
{
web.Dispose();
}

if (site != null)
{
site.Dispose();
}
}
}

Dec 19, 2007 at 9:14 PM
MembershipRequestControl class


//create the user in the Membership DB
protected override void OnCreatingUser(LoginCancelEventArgs e)
{
SPWeb web = SPControl.GetContextWeb(Context);
if (web.Featuresnew Guid("{69CE2076-9A2F-4c71-AEDF-F4252C01DE4E}") != null)
{
MembershipRequest request = new MembershipRequest();
request.UserEmail = this.Email;
request.UserName = this.UserName;
request.PasswordQuestion = this.Question;
request.PasswordAnswer = this.Answer;
request.FirstName = this.FirstName;
request.LastName = this.LastName;

MembershipRequest.CopyToReviewList(request);
this.MoveTo(this.CompleteStep);
}
else
{
base.OnCreatingUser(e);
}
}

//now create the user in the SharePoint site and associate groups
protected override void OnCreatedUser(EventArgs e)
{
SPWeb web = SPControl.GetContextWeb(Context);
if (web.Featuresnew Guid("{69CE2076-9A2F-4c71-AEDF-F4252C01DE4E}") != null)
{
MembershipRequest request = new MembershipRequest();
request.UserEmail = this.Email;
request.UserName = this.UserName;
request.PasswordQuestion = this.Question;
request.PasswordAnswer = this.Answer;
request.FirstName = this.FirstName;
request.LastName = this.LastName;
request.SiteURL = SPContext.Current.Web.Url.ToString();

MembershipRequest.AutoApproveMembership(request);
}
else
{
base.OnCreatedUser(e);
}
}

Dec 19, 2007 at 9:18 PM
I created a class that is specific to my company that I use for adding users to groups that you might find helpful as well, but it uses my BLL and DAL tiers. Let me know if you need more code to understand what I did when I was using those layers. This code is called from the ApproveMembership method in the MemberhipRequest class.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Security;
using Microsoft.SharePoint;
using System.Collections;
using CKS.Tracing;
using System.Web;
using System.Reflection;
using System.Data;
using Medmarc.SharePoint.BLL;
using Medmarc.SharePoint.DAL;

namespace CKS.FormsBasedAuthentication
{
public class SharePointGroupMembership
{
#region Fields

private List<string> _defaultGroups = new List<string>();
private string _UserName = String.Empty;

#endregion

#region Properties

private List<string> DefaultGroups
{
get { return _defaultGroups; }
set { _defaultGroups = value; }
}

public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}

#endregion

#region Constructors
public SharePointGroupMembership(string userName)
{
UserName = userName;
InitializeDefaultGroups();
}

private void InitializeDefaultGroups()
{
DefaultGroups.Add("Welcome to Medmarc Visitors");
}

#endregion

#region Methods

public void UpdateUserGroupMembership(SharePointGroupMembership request, SPWeb web)
{
request.AddUserToDefaultGroups(request, web);
request.UpdateMedmarcGroups(request, web);
}

#region Add Membership

private void AddUserToDefaultGroups(SharePointGroupMembership request, SPWeb web)
{
foreach (string group in DefaultGroups)
request.AddUserToGroup(request, web, group);
}

private void AddUserToGroup(SharePointGroupMembership request, SPWeb web, string groupName)
{
SPGroup spGroup = GetGroup(web, groupName);
SPUser spUser = web.AllUsersMembership.Provider.Name + ":" + request.UserName;

if (spGroup != null && spUser != null)
spGroup.AddUser(spUser);
}

private void UpdateMedmarcGroups(SharePointGroupMembership request, SPWeb web)
{
Medmarc.SharePoint.BLL.InfinitySharePointGroups infinityGroups = new InfinitySharePointGroups();
Infinity.WebGetUserRightsDataTable dtInfinityGroups = new Infinity.WebGetUserRightsDataTable();

SPUser spUser = web.AllUsersMembership.Provider.Name + ":" + request.UserName;
dtInfinityGroups = infinityGroups.SelectInfinitySharePointGroups(spUser.Email);

foreach (DataColumn col in dtInfinityGroups.Columns)
{
string test = String.Empty;
test = dtInfinityGroups.Rows0col.ColumnName.ToString();

if ((int) dtInfinityGroups.Rows0col.ColumnName == 1)
AddUserToGroup(request, web, col.ColumnName);
else
RemoveUserFromGroup(request, web, col.ColumnName);
}
}

#endregion

#region Remove Membership

//private void RemoveUserFromSharePointCollection(SharePointGroupMembership request, SPWeb web)
//{
// web.SiteUsers.Remove(Membership.Provider.Name + ":" + request.UserName);
//}

private void RemoveUserFromGroup(SharePointGroupMembership request, SPWeb web, string groupName)
{
SPGroup spGroup = GetGroup(web, groupName);
SPUser spUser = web.AllUsersMembership.Provider.Name + ":" + request.UserName;

if (spGroup != null && spUser != null)
spGroup.RemoveUser(spUser);
}

private SPGroup GetGroup(SPWeb web, string name)
{
foreach (SPGroup group in web.Groups)
if (group.Name.ToLower() == name.ToLower())
return group;
return null;
}

#endregion

#endregion

}
}
Dec 19, 2007 at 9:23 PM
I've already done that part, but thanks anyways.


cprimetrpt wrote:
Here you go:

MembershipRequest class

Dec 19, 2007 at 9:24 PM
And that was the part I was stumbling with. Thanks a lot!! I guess that'll do it.


cprimetrpt wrote:
MembershipRequestControl class

//now create the user in the SharePoint site and associate groups
protected override void OnCreatedUser(EventArgs e)
{
SPWeb web = SPControl.GetContextWeb(Context);
if (web.Featuresnew Guid("{69CE2076-9A2F-4c71-AEDF-F4252C01DE4E}") != null)
{
MembershipRequest request = new MembershipRequest();
request.UserEmail = this.Email;
request.UserName = this.UserName;
request.PasswordQuestion = this.Question;
request.PasswordAnswer = this.Answer;
request.FirstName = this.FirstName;
request.LastName = this.LastName;
request.SiteURL = SPContext.Current.Web.Url.ToString();

MembershipRequest.AutoApproveMembership(request);
}
else
{
base.OnCreatedUser(e);
}
}


Dec 19, 2007 at 9:27 PM
Saw already that you're calling a custom method to add users to WSS/MOSS groups. Didn't bother because I have something similar in place, although yours is way more elegant than mine.

Thanks for your help! Really appreciated!


cprimetrpt wrote:
I created a class that is specific to my company that I use for adding users to groups that you might find helpful as well, but it uses my BLL and DAL tiers. Let me know if you need more code to understand what I did when I was using those layers. This code is called from the ApproveMembership method in the MemberhipRequest class.