Archive

Posts Tagged ‘AllowUnsafeUpdates’

SharePoint: Wrapper over EnsureUser

May 3rd, 2011 Admin No comments

     When I needed to get SPUser-object I always utilized SPWeb.EnsureUser method. EnsureUser looks for the specified user login inside SPWeb.SiteUsers collection, and if the login isn’t found, turns to ActiveDirectory for the purpose of retrieving the user information from there. If such information is found, it will be added to SPWeb.SiteUsers and for the next time it will be returned directly from SPWeb.SiteUsers.

So, we have the fact that when EnsureUser is called, SPWeb-object potentially can be changed (changes affect SPWeb.SiteUsers collection, to be more precise). Each time we change SPWeb-object, it’s highly recommended to make sure that SPWeb.AllowUnsafeUpdates = true. It’s especially topical, when EnsureUser is called from Page during GET-request (Page.IsPostback = false). Otherwise, “Updates are currently disallowed on GET requests. To allow updates on a GET, set the ‘AllowUnsafeUpdates’ property on SPWeb” is thrown.

I’ve implemented some wrapper over the standard SPWeb.EnsureUser:

public static SPUser SafeEnsureUser(SPWeb web, string loginName)
{
    SPUser res = null;
    if (!web.AllowUnsafeUpdates)
    {
        bool oldAllowUnsafeUpdate = web.AllowUnsafeUpdates;
        try
        {
            web.AllowUnsafeUpdates = true;
            res = web.EnsureUser(loginName);
        }
        catch (Exception ex)
        {
            // write to log
        }
        finally
        {
            web.AllowUnsafeUpdates = oldAllowUnsafeUpdate;
        }
    }
    else
        try
        {
            res = web.EnsureUser(loginName);
        }
        catch(Exception ex)
        {
           // write to log
        }

    return res;
}

SafeEnsureUser checks whether web.AllowUnsafeUpdates is true. If yes, it just invoke standard EnsureUser. Otherwise, it preset web.AllowUnsafeUpdates to true and then invoke standard EnsureUser. Nowadays, everywhere I use this method instead of standard one.

If you need an extension for SPWeb-object, try this

public static SPUser SafeEnsureUser(this SPWeb web, string loginName)
{
	// the same method body
}
Related posts:

SharePoint: ResetRoleInheritance and BreakRoleInheritance wrappers

March 21st, 2011 Admin No comments

     A while back I wrote about a number of methods lead to reinitializing of SPWeb-object and, as the result, to resetting AllowUnsafeUpdates to false (SharePoint: Updates are currently disallowed on GET requests). Methods ResetRoleInheritance and BreakRoleInheritance of SPListItem class are the examples of such behavior. I use them very often, that is why I decided to develop a couple of wrappers that allow to restore AllowUnsafeUpdates to true automatically after original methods have finished their work.

public static void SafeResetRoleInheritance(SPListItem item)
{
    bool oldAllowUnsafeUpdate = item.Web.AllowUnsafeUpdates;
    item.ResetRoleInheritance();
    if(item.Web.AllowUnsafeUpdates != oldAllowUnsafeUpdate)
        item.Web.AllowUnsafeUpdates = oldAllowUnsafeUpdate;
}
public static void SafeBreakRoleInheritance(SPListItem item, bool copyRoleAssignments)
{
    bool oldAllowUnsafeUpdate = item.Web.AllowUnsafeUpdates;
    item.BreakRoleInheritance(copyRoleAssignments);
    if (item.Web.AllowUnsafeUpdates != oldAllowUnsafeUpdate)
        item.Web.AllowUnsafeUpdates = oldAllowUnsafeUpdate;
}

     Each wrapper preserves the current value of SPWeb.AllowUnsafeUpdates, invokes the original method, then tests whether the AllowUnsafeUpdates is changed and if so, it restores the old value back.

Related posts:

SharePoint: Updates are currently disallowed on GET requests

March 4th, 2011 Admin 8 comments

     When I need to set unique permissions to a SPListItem I usually use the code like the following:

using (SPSite spSite = new SPSite("some url"))
{
    using (SPWeb spWeb = spSite.OpenWeb())
    {
        bool oldAllowUnsafeUpdates = spWeb.AllowUnsafeUpdates;
        spWeb.AllowUnsafeUpdates = true;
        spWeb.Update();

        try
        {
            SPList spList = spWeb.Lists["some list"];

            SPListItem spLisItem = spList.GetItemById(someId);
            spLisItem.BreakRoleInheritance(false);

            SPRoleDefinition reader = spWeb.RoleDefinitions.GetByType(SPRoleType.Reader);
            SPGroup someGrp = spWeb.Groups["some group"];

            SPRoleAssignment roleAssignment = new SPRoleAssignment(someGrp);
            roleAssignment.RoleDefinitionBindings.Add(reader);
            spListItem.RoleAssignments.Add(roleAssignment); // (***) exception

        }
        catch (Exception ex)
        {
            // logging
        }

        spWeb.AllowUnsafeUpdates = oldAllowUnsafeUpdates;
    }
}

     It works fine almost everywhere: in feature receivers, in jobs, in console applications and so on. But today I’ve found out that it doesn’t work correctly if it runs from aspx-page’s code-behind when we have GET request (Page.IsPostBack = false). In the line marked (***) I receives a traditional exception – “Updates are currently disallowed on GET requests. To allow updates on a GET, set the ‘AllowUnsafeUpdates’ property on SPWeb”. As you can see I set spWeb.AllowUnsafeUpdates to true and even do spWeb.Update() (though it’s unnecessary in most cases), but nothing helps. Wrapping this code in SPSecurity.RunWithElevatedPrivileges doesn’t help either.

     After debugging for a while I’ve noticed that spWeb.AllowUnsafeUpdates gets false after spLisItem.BreakRoleInheritance:

// here spWeb.AllowUnsafeUpdates = true
spLisItem.BreakRoleInheritance(false);
// here spWeb.AllowUnsafeUpdates = false

     It should be noted that the same happens when we have a POST request (Page.IsPostback = true), but in this case it doesn’t cause exception. Interestingly that we have some kind of special treatment for GET request here :)

     The reason of such behavior has been found, as usual, by means of .NET Reflector. Not going into details I say that the calling of BreakRoleInheritance leads to the calling of Invalidate() method of SPWeb. Let’s take a look at this method:

internal void Invalidate()
{
    this.ReleasePinnedResource();
    if (this.m_Request != null)
    {
        if (this.m_RequestOwnedByThisWeb)
        {
            SPRequestManager.Release(this.m_Request);
        }
        this.m_Request = null;
    }
    this.m_bInited = false;
    this.m_bPublicPropertiesInited = false;
    this.m_Url = null;
}

     It looks like Invalidate releases some resources and cleans itself (m_bInited = false), in the same time, doesn’t dispose itself, but just provokes reinitializing during the next address to it. After reinitialization spWeb.AllowUnsafeUpdates turns into false. An evident workaround is to set true to spWeb.AllowUnsafeUpdates again after BreakRoleInheritance.

// some code is skipped
spLisItem.BreakRoleInheritance(false);
spWeb.AllowUnsafeUpdates = true;
spWeb.Update();
// some code is skipped

     I think there are many methods, which can cause SPWeb.Invalidate, for example, ResetRoleInheritance does the same, and, in a few special cases, SPWeb.Update either. That is why be ready to add restoring of AllowUnsafeUpdates to true. I hope this post will save time for somebody.

Related posts: