Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizations to "TokenParser" #964

Merged
merged 9 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.35.0" />
</ItemGroup>

<ItemGroup>
Expand Down
89 changes: 51 additions & 38 deletions src/lib/PnP.Framework/Extensions/ClientContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
using PnP.Framework;
using PnP.Framework.Diagnostics;
using PnP.Framework.Http;
using PnP.Framework.Provisioning.ObjectHandlers;
using PnP.Framework.Sites;
using PnP.Framework.Utilities;
using PnP.Framework.Utilities.Async;
using PnP.Framework.Utilities.Context;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand All @@ -21,6 +12,14 @@
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using PnP.Framework;
using PnP.Framework.Diagnostics;
using PnP.Framework.Http;
using PnP.Framework.Provisioning.ObjectHandlers;
using PnP.Framework.Sites;
using PnP.Framework.Utilities;
using PnP.Framework.Utilities.Async;
using PnP.Framework.Utilities.Context;

namespace Microsoft.SharePoint.Client
{
Expand All @@ -29,10 +28,11 @@ namespace Microsoft.SharePoint.Client
/// </summary>
public static partial class ClientContextExtensions
{
private static readonly string userAgentFromConfig = null;
private static readonly string UserAgentFromConfig;
private static readonly Lazy<PropertyInfo> PendingRequestActionsProperty = new Lazy<PropertyInfo>(GetPendingRequestActionsProperty);

#pragma warning disable CS0169
private static ConcurrentDictionary<string, (string requestDigest, DateTime expiresOn)> requestDigestInfos = new ConcurrentDictionary<string, (string requestDigest, DateTime expiresOn)>();
private static readonly ConcurrentDictionary<string, (string requestDigest, DateTime expiresOn)> RequestDigestInfos = new ConcurrentDictionary<string, (string requestDigest, DateTime expiresOn)>();
#pragma warning restore CS0169

//private static bool hasAuthCookies;
Expand All @@ -45,15 +45,15 @@ static ClientContextExtensions()
{
try
{
ClientContextExtensions.userAgentFromConfig = ConfigurationManager.AppSettings["SharePointPnPUserAgent"];
UserAgentFromConfig = ConfigurationManager.AppSettings["SharePointPnPUserAgent"];
}
catch // throws exception if being called from a .NET Standard 2.0 application
{

}
if (string.IsNullOrWhiteSpace(ClientContextExtensions.userAgentFromConfig))

if (string.IsNullOrWhiteSpace(UserAgentFromConfig))
{
ClientContextExtensions.userAgentFromConfig = Environment.GetEnvironmentVariable("SharePointPnPUserAgent", EnvironmentVariableTarget.Process);
UserAgentFromConfig = Environment.GetEnvironmentVariable("SharePointPnPUserAgent", EnvironmentVariableTarget.Process);
}
}
#pragma warning restore CA1810
Expand Down Expand Up @@ -303,9 +303,9 @@ private static EventHandler<WebRequestEventArgs> AttachRequestUserAgent(string c
}
if (overrideUserAgent)
{
if (string.IsNullOrEmpty(customUserAgent) && !string.IsNullOrEmpty(ClientContextExtensions.userAgentFromConfig))
if (string.IsNullOrEmpty(customUserAgent) && !string.IsNullOrEmpty(UserAgentFromConfig))
{
customUserAgent = userAgentFromConfig;
customUserAgent = UserAgentFromConfig;
}
e.WebRequestExecutor.WebRequest.UserAgent = string.IsNullOrEmpty(customUserAgent) ? $"{PnPCoreUtilities.PnPCoreUserAgent}" : customUserAgent;
}
Expand Down Expand Up @@ -518,24 +518,32 @@ internal static ClientContext Clone(this ClientRuntimeContext clientContext, Cli
/// </summary>
/// <param name="clientContext">Client context to check the pending requests for</param>
/// <returns>The number of pending requests</returns>
/// <exception cref="NotSupportedException">The currently loaded version of CSOM is not supported.</exception>
public static int PendingRequestCount(this ClientRuntimeContext clientContext)
{
int count = 0;
if (!clientContext.HasPendingRequest)
{
return 0;
}

if (clientContext.HasPendingRequest)
PropertyInfo property = PendingRequestActionsProperty.Value;
if (property == null)
{
var result = clientContext.PendingRequest.GetType().GetProperty("Actions", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic);
if (result != null)
{
var propValue = result.GetValue(clientContext.PendingRequest);
if (propValue != null)
{
count = (propValue as List<ClientAction>).Count;
}
}
return 0;
}

return count;
object rawValue = property.GetValue(clientContext.PendingRequest);
switch (rawValue)
{
case ICollection<ClientAction> actions:
return actions.Count;

case null:
return 0;

default:
throw new NotSupportedException("The currently loaded version of CSOM is not supported.");
}
}

/// <summary>
Expand Down Expand Up @@ -783,20 +791,20 @@ public static async Task<string> GetRequestDigestAsync(this ClientContext contex
if (cookieContainer != null)
{
var hostUrl = context.Url;
if (requestDigestInfos.TryGetValue(hostUrl, out (string digestToken, DateTime expiresOn) requestDigestInfo))
if (RequestDigestInfos.TryGetValue(hostUrl, out (string digestToken, DateTime expiresOn) requestDigestInfo))
{
// We only have to add a request digest when running in dotnet core
if (DateTime.Now > requestDigestInfo.expiresOn)
{
requestDigestInfo = await GetRequestDigestInfoAsync(hostUrl, cookieContainer);
requestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
RequestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
}
}
else
{
// admin url maybe?
requestDigestInfo = await GetRequestDigestInfoAsync(hostUrl, cookieContainer);
requestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
RequestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
}
return requestDigestInfo.digestToken;
}
Expand Down Expand Up @@ -856,20 +864,20 @@ public static async Task<string> GetRequestDigestAsync(this ClientContext contex
public static async Task<string> GetRequestDigestAsync(this ClientContext context)
{
var hostUrl = context.Url;
if (requestDigestInfos.TryGetValue(hostUrl, out (string digestToken, DateTime expiresOn) requestDigestInfo))
if (RequestDigestInfos.TryGetValue(hostUrl, out (string digestToken, DateTime expiresOn) requestDigestInfo))
{
// We only have to add a request digest when running in dotnet core
if (DateTime.Now > requestDigestInfo.expiresOn)
{
requestDigestInfo = await GetRequestDigestInfoAsync(context);
requestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
RequestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
}
}
else
{
// admin url maybe?
requestDigestInfo = await GetRequestDigestInfoAsync(context);
requestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
RequestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
}
return requestDigestInfo.digestToken;
}
Expand Down Expand Up @@ -932,20 +940,20 @@ public static async Task<string> GetRequestDigestAsync(this ClientContext contex
internal static async Task<string> GetOnPremisesRequestDigestAsync(this ClientContext context)
{
var hostUrl = context.Url;
if (requestDigestInfos.TryGetValue(hostUrl, out (string digestToken, DateTime expiresOn) requestDigestInfo))
if (RequestDigestInfos.TryGetValue(hostUrl, out (string digestToken, DateTime expiresOn) requestDigestInfo))
{
// We only have to add a request digest when running in dotnet core
if (DateTime.Now > requestDigestInfo.expiresOn)
{
requestDigestInfo = await GetOnPremisesRequestDigestInfoAsync(context);
requestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
RequestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
}
}
else
{
// admin url maybe?
requestDigestInfo = await GetOnPremisesRequestDigestInfoAsync(context);
requestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
RequestDigestInfos.AddOrUpdate(hostUrl, requestDigestInfo, (key, oldValue) => requestDigestInfo);
}
return requestDigestInfo.digestToken;
}
Expand Down Expand Up @@ -1181,5 +1189,10 @@ internal static CookieContainer GetAuthenticationCookies(this ClientContext cont
}
return authCookiesContainer;
}

private static PropertyInfo GetPendingRequestActionsProperty()
{
return typeof(ClientRequest).GetProperty("Actions", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate templ
}
}

IEnumerable<AssociatedGroupToken> associatedGroupTokens = parser.Tokens.Where(t => t.GetType() == typeof(AssociatedGroupToken)).Cast<AssociatedGroupToken>();
IEnumerable<AssociatedGroupToken> associatedGroupTokens = parser.Tokens.OfType<AssociatedGroupToken>();
foreach (AssociatedGroupToken associatedGroupToken in associatedGroupTokens)
{
associatedGroupToken.ClearCache();
Expand Down
Loading
Loading