SharePoint 2016 Logo

For a process I had to update the Author field in SharePoint online list item. This time I decided to use PnP.Core instead of PnP.Framework. Was it worth it? I don't really know, but the method is not the most difficult part of the task.

When I made this method, I created at least 2 solutions. Probably, more, but I did lots of experiments and troubleshooting.

1. with PnP.Core

        [HttpGet("updateauthor")]
        public async Task<IActionResult> UpdateAuthor()
        {
            var siteUrl = _settings.SitesSettings.MySite.SiteUrl;
            var listTitle = _settings.SitesSettings.MySite.ListTitle;

            using (var context = await _pnpContextFactory.CreateAsync(new Uri(siteUrl), _authenticationProvider))
            {
                var list = await context.Web.Lists.GetByTitleAsync(listTitle);
                var item = await list.Items.GetByIdAsync(186, p => p["Author"]);
                item.Values["Author"] = 6;
                await item.UpdateOverwriteVersionAsync();
                await context.ExecuteAsync();
            }
            return Ok("Authentication updated successfully.");
        }

'userId = 6' is my Id at the web. I wanted to be sure that I can update the value.

2. With CSOM

public async Task<IActionResult> SetAuthorCSOMRest(int itemId, int userId)
{
    var siteUrl = _settings.SitesSettings.MySite.SiteUrl;
            var listTitle = _settings.SitesSettings.MySite.ListTitle;
    var clientContext = await _appContext.GetContextAsync(siteUrl);

    var listItem = clientContext.Web.Lists.GetByTitle(listTitle).GetItemById(itemId);
    clientContext.Load(listItem, i => i["Author"], i => i["Editor"], i=> i["Title"]);
    await clientContext.ExecuteQueryAsync();
    Microsoft.SharePoint.Client.FieldUserValue userValue = new Microsoft.SharePoint.Client.FieldUserValue()
    {
        LookupId = userId
    };
    
    listItem["Author"] = userValue;
    listItem.SystemUpdate();
    clientContext.ExecuteQueryAsync();
    
    return Ok($"Author updated successfully for item {itemId} in list {listTitle}.");
}
 .... 
          await SetAuthorCSOMRest(187, 6);

Much more interesting is how to make AuthenticationProvider and set the permissions for the App.

I added it into the main Class and registered as a dependency

using PnP.Core.Services;
...
builder.Services.AddSingleton<IAuthenticationProvider>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    var settings = sp.GetRequiredService<IOptions<HAppSettings>>().Value;

    var vaultUri = $"https://{settings.KeyVaultSettings.VaultName}.vault.azure.net/";
    var certName = settings.KeyVaultSettings.CertificateName;

    var secretClient = new SecretClient(new Uri(vaultUri), new DefaultAzureCredential());
    var secret = secretClient.GetSecret(certName);
    var certBytes = Convert.FromBase64String(secret.Value.Value);
    var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certBytes, "", X509KeyStorageFlags.MachineKeySet);

    return new X509CertificateAuthenticationProvider(
        settings.KeyVaultSettings.ClientId,
        settings.KeyVaultSettings.TenantId,
        cert
    );
});

The most important thing is that you (your service account) need fullcontrol permissions to the specific site.