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.
public static class SPListItemExtension
{
public static void UpdateDisableItemEvents(this SPListItem item)
{
using (DisabledItemEventsScope scope = new DisabledItemEventsScope())
{
item.Update();
}
}
}
and call it in your code as follows:
item.UpdateDisableItemEvents();