How do I create a second context?
-
30-01-2021 - |
Pregunta
How do I create a second context pointing to another sitecollection (still same domain) by using the logged in user's credentials in SharePointOnline with CSOM C#? I don't want to login a second time.
This is how far I've got so far. But "currUser"'s Credentials is null.
var uri = new Uri(adress to my subsite)
var ctx2 = new ClientContext(uri);
var currUser = ctx.Web.CurrentUser;
ctx.Load(currUser );
ctx.ExecuteQuery();
ctx.Web.EnsureUser(currUser.LoginName);
ctx2.Credentials = currUser.Context.Credentials;
Solución
You can either add PnP-Sites-Core
via nuget as dependency and use extension method Clone
:
var newctx = clientContext.Clone("https://new url");
or just add below method in your code base (I grabbed it from here):
/// <summary>
/// Clones a ClientContext object while "taking over" the security context of the existing ClientContext instance
/// </summary>
/// <param name="clientContext">ClientContext to be cloned</param>
/// <param name="siteUrl">Site URL to be used for cloned ClientContext</param>
/// <param name="accessTokens">Dictionary of access tokens for sites URLs</param>
/// <returns>A ClientContext object created for the passed site URL</returns>
public static ClientContext Clone(this ClientRuntimeContext clientContext, Uri siteUrl, Dictionary<String, String> accessTokens = null)
{
if (siteUrl == null)
{
throw new ArgumentException(CoreResources.ClientContextExtensions_Clone_Url_of_the_site_is_required_, nameof(siteUrl));
}
ClientContext clonedClientContext = new ClientContext(siteUrl);
clonedClientContext.AuthenticationMode = clientContext.AuthenticationMode;
clonedClientContext.ClientTag = clientContext.ClientTag;
// In case of using networkcredentials in on premises or SharePointOnlineCredentials in Office 365
if (clientContext.Credentials != null)
{
clonedClientContext.Credentials = clientContext.Credentials;
}
else
{
//Take over the form digest handling setting
clonedClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled;
var originalUri = new Uri(clientContext.Url);
// If the cloned host is not the same as the original one
// and if there is a custom Access Token for it in the input arguments
if (originalUri.Host != siteUrl.Host &&
accessTokens != null && accessTokens.Count > 0 &&
accessTokens.ContainsKey(siteUrl.Authority))
{
// Let's apply that specific Access Token
clonedClientContext.ExecutingWebRequest += (sender, args) =>
{
args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessTokens[siteUrl.Authority];
};
}
else
{
// In case of app only or SAML
clonedClientContext.ExecutingWebRequest += delegate (object oSender, WebRequestEventArgs webRequestEventArgs)
{
// Call the ExecutingWebRequest delegate method from the original ClientContext object, but pass along the webRequestEventArgs of
// the new delegate method
MethodInfo methodInfo = clientContext.GetType().GetMethod("OnExecutingWebRequest", BindingFlags.Instance | BindingFlags.NonPublic);
object[] parametersArray = new object[] { webRequestEventArgs };
methodInfo.Invoke(clientContext, parametersArray);
};
}
}
return clonedClientContext;
}
Otros consejos
If the subweb is under the same site collection you can use the same context to get it.
Here's the example:
Site site = ctx.Site;
ctx.Load(site);
ctx.ExecuteQuery();
var p = ResourcePath.FromDecodedUrl("/relative/path/to/subweb");
var subweb = site.OpenWebUsingPath(p);
ctx.ExecuteQuery();
ctx.Load(subweb, w => w.Url);
ctx.ExecuteQuery();
//here you have the subweb object pointing to the Web
EDIT: In the case of different site collection, you should be able to do something like this:
var siteUrl = "https://anothersitecollectionurl";
var ctx2 = new ClientContext(siteUrl);
ctx2.Credentials = ctx.Credentials;
This works in the windows application, where the first context object (ctx
) has been logged in by explicitly providing the username/password combination.