views:

1414

answers:

4

We have a web part that uploads a document to a document library. The user uploading the document may not have access to the destination location, so the code adding the file executes within a RunWithElevatedPrivileges block. This means the "Modified By" field is always set to System Account. Here is the code:

SPSecurity.RunWithElevatedPrivileges(
    delegate
    {
     using (SPSite elevatedSite = new SPSite(SPContext.Current.Site.Url))
     using (SPWeb targetWeb = elevatedSite.OpenWeb(webUrl))
     {
      targetWeb.AllowUnsafeUpdates = true;
      SPFile newFile = files.Add(filename, file);
      SPListItem item = newFile.Item;

      // TODO: Insert code to set Modified By

      item.SystemUpdate();
     }
    }
}

The "Modified By" field needs to be set to the name of the current user (at the TODO line above), but none of the following attempts have worked:

item["Modified By"] = SPContext.Current.Web.CurrentUser;

item["Author"] = SPContext.Current.Web.CurrentUser;

item["Modified By"] = new SPFieldUserValue(
SPContext.Current.Web, SPContext.Current.Web.CurrentUser.ID,
SPContext.Current.Web.CurrentUser.Name);

item["Author"] = new SPFieldUserValue(
SPContext.Current.Web, SPContext.Current.Web.CurrentUser.ID,
SPContext.Current.Web.CurrentUser.Name);

Does anyone know of a solution that allows the "Modified By" value to be changed?

+4  A: 

I've come across this problem and the workaround I found was to keep in memory the current user and later replace the System Account with it.

See below:

// Keep the 'real' current user
SPUser currentUser = SPContext.Current.Web.CurrentUser;

SPSecurity.RunWithElevatedPrivileges(
delegate
{
    using (SPSite elevatedSite = new SPSite(SPContext.Current.Site.Url))
    using (SPWeb targetWeb = elevatedSite.OpenWeb(webUrl))
    {
        targetWeb.AllowUnsafeUpdates = true;
        SPFile newFile = files.Add(filename, file);
        SPListItem item = newFile.Item;

        // Replace 'System Account' with current user
        item["Author"] = currentUser;
        item["Modified By"] = currentUser;

        item.SystemUpdate();
    }
});

I hope this helps.

Henrique Zacchi
Do not forget to set targetWeb.AllowUnsafeUpdates to false. You would like to do that in finally {} block.
Janis Veinbergs
A: 

Perhaps impersonation might be an option helping you to solve your problem.

Some infos on that: http://dotnet.org.za/zlatan/archive/2007/08/05/sharepoint-2007-impersonation.aspx http://www.sharepointblogs.com/mirjam/archive/2006/11/02/impersonation-in-sharepoint-2007.aspx

Flo
A: 

Have you tried this instead of SPSecurity.RunWithElevatedPrivileges?

using (WindowsImpersonationContext w = WindowsIdentity.Impersonate(IntPtr.Zero)) 
{
     //Do stuff here
}
JMD
+1  A: 

I did some more testing...

item["Editor"] = SPContext.Current.Web.CurrentUser;
item["Author"] = SPContext.Current.Web.CurrentUser;
item.SystemUpdate();

Created By is set to the current user but Modified By is set to System Account.

item["Editor"] = SPContext.Current.Web.CurrentUser;
item["Author"] = SPContext.Current.Web.CurrentUser;
item.Update();

Both Created By and Modified By are set to the current user.

The problem was using SPListItem.SystemUpdate() which does the exact opposite of what the API documentation states, at least when running with elevated privileges.

Note: SPContext.Current.Web.CurrentUser does pick up the current user and not the system account when running within SPSecurity.RunWithElevatedPrivileges. (Whether it should be used like this is another question.)

Alex Angas