SharePoint: Updates are currently disallowed on GET requests
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.