Friday, March 28, 2014

Using Membership Provider in SharePoint 2010 Event Receiver

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.

Tuesday, March 18, 2014

Update Modified By field in sharepoint 2010 list


Sometimes we need to insert/update item using
“SPSecurity.RunWithElevatedPrivileges(delegate(){});” for getting the Administrator privilege..

But as a result of that we see the “System Account” as a value of "Modified By" field of that inserted/updated item, instead of the original user who actually did the modification.

In this case, we need to update the "Modified By" field in the time of inserting/updating. It may not work if we assign a value for the "Modified By" field and call the Update method.

So we have to use the "UpdateOverwriteVersion()" method. This method allows for the setting of properties on a SPListItem object without creating a separate version of the item. This method also allows for setting of certain system properties such as Created(date), Modified(date), Author(Created By) and Editor(Modifies By).

These are the following code by which we can easily update Modified By field:-

using (SPSite oSite = new SPSite(SPContext.Current.Web.Url))


 {
   using (SPWeb oWeb = oSite.OpenWeb())
   {
      //Variable to store the user
      SPUser oUser = oWeb.CurrentUser;
      oWeb.AllowUnsafeUpdates = true;

      SPFieldUserValue userVal = new SPFieldUserValue(oWeb, oUser.ID, oUser.LoginName);

      SPList oList = oWeb.Lists["ListName"];
      SPListItem oItem = oList.GetItemById(Item Id);

      oItem["Modified By"] = userVal;
                OR
      oItem[SPBuiltInFieldId.Editor] = userVal;
                OR
      oItem[“Editor”] = userVal;

      oItem.UpdateOverwriteVersion();

      oWeb.AllowUnsafeUpdates = false;
   }
}