Jan 16, 2011

Accessing Membership database inside SharePoint 2010 SPList event handler

If we have Claims-based authentication and Membership database hooked in the SharePoint, a very common scenario could be adding new user to the membership database within SPList event handler (let’s say in ItemAdding). We would like to check there if the user already exists there, if so to redirect to our custom error page, of not – just add it to the membership database.

Well, if you just try to access the membership database and fetch all the users you will end up with “NullReferenceException”.



Well, if you dig around about problems like this, you can see some helpful posts stating that HtppContext is null in the Event handlers for SharePoint list.
Could that be the reason? And that is weird, because we instantly would ask ourselves – what has SqlMembershipProvider in common with the HttpContext? And the natural answer of course is – nothing (well, GetCurrentUserName() relies, but if we take a look in its body, it should definitely not bring to null reference exception).

But, if we really take a look at the stack trace of the exception we will see that what is called is not the method of SqlMembershipProvider, but the method of SPClaimsAuthMembershipProvider.
If we open the reflector and see what’s happening in its methods, we will get answered right away!
StackTrace:
at Microsoft.SharePoint.Administration.Claims.SPClaimsAuthProviderUtility.GetPassthroughMembershipProvider()
at Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider.GetAllUsers(Int32 pageIndex, Int32 pageSize, Int32& totalRecords)
at System.Web.Security.Membership.GetAllUsers()
at MySolution.Code.EventHandlers.RegisterUsersEventHandlers.<>c__DisplayClass1.b__0()
at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.b__2()
at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)


If we use the reflector and check the body of called methods we will see next:





And the reason for calling SPClaimsAuthMembershipProvider is the fact that it is the default provider used according the web.config of our application.



Knowing what the reason is, makes fixing the problem achievable in 2 different ways. Let’s quickly review the solutions:

Solutions:
1)Continue to rely on SPClaimsAuthMembershipProvider and obtaining HttpContext.Current

Just instantiate the HttContext.Current If it is null:

if (HttpContext.Current == null)
{
HttpRequest request = new HttpRequest(String.Empty, sp_web.Url, String.Empty);
HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter()));
}



If you instantiated new HttpContext, it would be good to reset it at the end of your methods back to null. Just make sure this happens only if HttpContext.Current was null at the beginning.

2)Working with the SqlMembershipProvider and forgetting about HttpContext.Current issue

What we need is to get the SqlMembershipProvider from registered providers and to start using it.
SqlMembershipProvider sqlMembershipProvider = (SqlMembershipProvider)Membership.Providers["FBAMembershipProvider"];

Bear in mind that you should put the name as it is in your web.config file.

2 comments:

  1. Just what I was looking for! Very useful, thanks!

    Best regards,
    Ignat

    ReplyDelete