fix(site-list): fix parsing error and double-auth in SiteListService
- Replace GetSitePropertiesFromSharePoint("", true) with modern
GetSitePropertiesFromSharePointByFilters using null StartIndex
- Use ctx.Clone(adminUrl) instead of creating new AuthenticationManager
for admin URL, eliminating second browser auth prompt
Resolves: UAT issue "Must specify valid information for parsing in the string"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,18 +27,12 @@ public class SiteListService : ISiteListService
|
||||
ct.ThrowIfCancellationRequested();
|
||||
progress.Report(OperationProgress.Indeterminate("Loading sites..."));
|
||||
|
||||
var adminUrl = DeriveAdminUrl(profile.TenantUrl);
|
||||
var adminProfile = new TenantProfile
|
||||
{
|
||||
Name = profile.Name,
|
||||
TenantUrl = adminUrl,
|
||||
ClientId = profile.ClientId
|
||||
};
|
||||
|
||||
ClientContext adminCtx;
|
||||
// Obtain the already-authenticated context for the tenant URL, then clone it to
|
||||
// the admin URL. Cloning reuses the existing token — no second interactive login.
|
||||
ClientContext ctx;
|
||||
try
|
||||
{
|
||||
adminCtx = await _sessionManager.GetOrCreateContextAsync(adminProfile, ct);
|
||||
ctx = await _sessionManager.GetOrCreateContextAsync(profile, ct);
|
||||
}
|
||||
catch (ServerException ex) when (ex.Message.Contains("Access denied", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -46,19 +40,41 @@ public class SiteListService : ISiteListService
|
||||
"Site listing requires SharePoint administrator permissions. Connect with an admin account.", ex);
|
||||
}
|
||||
|
||||
var adminUrl = DeriveAdminUrl(profile.TenantUrl);
|
||||
using var adminCtx = ctx.Clone(adminUrl);
|
||||
|
||||
var results = new List<SiteInfo>();
|
||||
var tenant = new Tenant(adminCtx);
|
||||
var siteProps = tenant.GetSitePropertiesFromSharePoint("", true);
|
||||
adminCtx.Load(siteProps);
|
||||
await adminCtx.ExecuteQueryAsync();
|
||||
SPOSitePropertiesEnumerable? batch = null;
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
// Paginate through all site collections using GetSitePropertiesFromSharePointByFilters.
|
||||
// StartIndex = null on the first call; subsequent calls use NextStartIndexFromSharePoint.
|
||||
while (batch == null || batch.NextStartIndexFromSharePoint != null)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
return siteProps
|
||||
.Where(s => s.Status == "Active"
|
||||
&& !s.Url.Contains("-my.sharepoint.com", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(s => new SiteInfo(s.Url, s.Title))
|
||||
.OrderBy(s => s.Url)
|
||||
.ToList();
|
||||
var filter = new SPOSitePropertiesEnumerableFilter
|
||||
{
|
||||
IncludePersonalSite = PersonalSiteFilter.UseServerDefault,
|
||||
StartIndex = batch?.NextStartIndexFromSharePoint,
|
||||
IncludeDetail = true
|
||||
};
|
||||
|
||||
batch = tenant.GetSitePropertiesFromSharePointByFilters(filter);
|
||||
adminCtx.Load(batch);
|
||||
await adminCtx.ExecuteQueryAsync();
|
||||
|
||||
foreach (var s in batch)
|
||||
{
|
||||
if (s.Status == "Active"
|
||||
&& !s.Url.Contains("-my.sharepoint.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
results.Add(new SiteInfo(s.Url, s.Title));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results.OrderBy(s => s.Url).ToList();
|
||||
}
|
||||
|
||||
internal static string DeriveAdminUrl(string tenantUrl)
|
||||
|
||||
Reference in New Issue
Block a user