diff --git a/src/Commands/Base/InvokeQuery.cs b/src/Commands/Base/InvokeQuery.cs index 413f03eff..83208e790 100644 --- a/src/Commands/Base/InvokeQuery.cs +++ b/src/Commands/Base/InvokeQuery.cs @@ -7,6 +7,8 @@ namespace PnP.PowerShell.Commands.Base [OutputType(typeof(void))] public class InvokeQuery : PnPSharePointCmdlet { + protected override bool ShouldRefreshContextWithPendingRequest => false; + [Parameter(Mandatory = false)] public int RetryCount = 10; diff --git a/src/Commands/Base/PnPConnection.cs b/src/Commands/Base/PnPConnection.cs index 4448ff91a..728cf5b0c 100644 --- a/src/Commands/Base/PnPConnection.cs +++ b/src/Commands/Base/PnPConnection.cs @@ -807,7 +807,7 @@ private PnPConnection(ClientContext context, PSCredential = credential; PnPVersionTag = pnpVersionTag; - ContextCache = new List { context }; + ContextCache = context != null ? new List { context } : new List(); if (!string.IsNullOrEmpty(url)) { Url = new Uri(url).AbsoluteUri; @@ -821,7 +821,7 @@ private PnPConnection(ClientContext context, #region Methods internal void RestoreCachedContext(string url) { - Context = ContextCache.FirstOrDefault(c => new Uri(c.Url).AbsoluteUri == new Uri(url).AbsoluteUri); + Context = ContextCache.FirstOrDefault(c => c != null && new Uri(c.Url).AbsoluteUri == new Uri(url).AbsoluteUri); _pnpContext = null; } @@ -829,22 +829,68 @@ internal void CacheContext() { if (Context == null) return; - var c = ContextCache.FirstOrDefault(cc => new Uri(cc.Url).AbsoluteUri == new Uri(Context.Url).AbsoluteUri); + ContextCache ??= new List(); + var c = ContextCache.FirstOrDefault(cc => cc != null && new Uri(cc.Url).AbsoluteUri == new Uri(Context.Url).AbsoluteUri); if (c == null) { ContextCache.Add(Context); } } + internal bool RefreshContextIfHasPendingRequest() + { + if (Context?.HasPendingRequest != true) + { + return false; + } + + RefreshContext(); + return true; + } + + internal void RefreshContext() + { + if (Context == null) + { + return; + } + + var context = Context.Clone(Context.Url); + ReplaceCachedContext(context); + + Context = context; + _pnpContext = null; + } + + private static void ReplaceCachedContext(ClientContext context) + { + ContextCache ??= new List(); + + var contextIndex = ContextCache.FindIndex(c => c != null && new Uri(c.Url).AbsoluteUri == new Uri(context.Url).AbsoluteUri); + if (contextIndex >= 0) + { + ContextCache[contextIndex] = context; + } + else + { + ContextCache.Add(context); + } + } + internal ClientContext CloneContext(string url) { - var context = ContextCache.FirstOrDefault(c => new Uri(c.Url).AbsoluteUri == new Uri(url).AbsoluteUri); + var context = ContextCache.FirstOrDefault(c => c != null && new Uri(c.Url).AbsoluteUri == new Uri(url).AbsoluteUri); if (context == null) { context = Context.Clone(url); context.ExecuteQueryRetry(); ContextCache.Add(context); } + else if (context.HasPendingRequest) + { + context = context.Clone(context.Url); + ReplaceCachedContext(context); + } _pnpContext = null; return context; } diff --git a/src/Commands/Base/PnPSharePointCmdlet.cs b/src/Commands/Base/PnPSharePointCmdlet.cs index adfeabd6b..86acfaf7f 100644 --- a/src/Commands/Base/PnPSharePointCmdlet.cs +++ b/src/Commands/Base/PnPSharePointCmdlet.cs @@ -22,6 +22,12 @@ public abstract class PnPSharePointCmdlet : PnPConnectedCmdlet /// public ClientContext ClientContext => Connection?.Context; + /// + /// Controls whether a cmdlet should replace the current SharePoint context when it already contains pending CSOM requests before the cmdlet starts. + /// Override this for cmdlets that intentionally execute caller-created pending requests. + /// + protected virtual bool ShouldRefreshContextWithPendingRequest => true; + /// /// Reference the the PnP context on the current connection. If NULL it means there is no PnP context available on the current connection. /// @@ -128,6 +134,12 @@ protected override void BeginProcessing() throw new InvalidOperationException(Resources.NoDefaultSharePointConnection); } } + + if (ShouldRefreshContextWithPendingRequest && Connection.RefreshContextIfHasPendingRequest()) + { + LogDebug("Refreshing the SharePoint context because it contained pending CSOM requests before cmdlet execution."); + } + var resourceUri = new Uri(Connection.Url); var defaultResource = $"{resourceUri.Scheme}://{resourceUri.Authority}/.default"; SharePointRequestHelper = new ApiRequestHelper(GetType(), Connection, defaultResource);