远程服务器在特定时间后返回错误:(401)未授权 - CSOM - OAuth

时间:2018-05-11 07:19:08

标签: sharepoint console-application office365 csom

我正在尝试使用控制台应用程序中的csom从文档库中获取分配给每个文档的权限。控制台应用程序正常运行了近一个小时并发布我收到错误:"远程服务器返回错误:(401)未经授权。"

我在SharePoint中注册了一个应用,并且我使用了Client ID&客户端密钥生成客户端上下文。以下是获取客户端上下文的代码

public static ClientContext getClientContext()
    {
        ClientContext ctx = null;
        try
        {
            ctx = new AuthenticationManager().GetAppOnlyAuthenticatedContext(SiteUrl, ClientId, ClientSecret);
            ctx.RequestTimeout = 6000000;

            ctx.ExecutingWebRequest += delegate (object sender, WebRequestEventArgs e)
            {
                e.WebRequestExecutor.WebRequest.UserAgent = "NONISV|Contoso|GovernanceCheck/1.0";
            };
        }
        catch (Exception ex)
        {
            WriteLog("Method-getClientContext, Error - " + ex.Message);
        }
        return ctx;
    }

以下是获取分配给文档库中文档的所有作业的代码。

static StringBuilder excelData = new StringBuilder();            
static void ProcessWebnLists()
    {
        try
        {
            string[] lists = { "ABC", "XYZ", "DEF", "GHI"};

            foreach (string strList in lists)
            {
                using (var ctx = getClientContext())
                {
                    if (ctx != null)
                    {
                        Web web = ctx.Site.RootWeb;
                        ListCollection listCollection = web.Lists;
                        ctx.Load(web);
                        ctx.Load(listCollection);
                        ctx.ExecuteQuery();

                        List list = web.Lists.GetByTitle(strList);
                        ctx.Load(list);
                        ctx.ExecuteQuery();

                        Console.WriteLine("List Name:{0}", list.Title);

                        var query = new CamlQuery { ViewXml = "<View/>" };

                        var items = list.GetItems(query);
                        ctx.Load(items);
                        ctx.ExecuteQuery();

                        foreach (var item in items)
                        {
                            var itemAssignments = item.RoleAssignments;
                            ctx.Load(item, i => i.DisplayName);
                            ctx.Load(itemAssignments);
                            ctx.ExecuteQuery();
                            Console.WriteLine(item.DisplayName);
                            string groupNames = "";
                            foreach (var assignment in itemAssignments)
                            {
                                try
                                {
                                    ctx.Load(assignment.Member);
                                    ctx.ExecuteQuery();
                                    groupNames += "[" + assignment.Member.Title.Replace(",", " ") + "] ";
                                    Console.WriteLine($"--> {assignment.Member.Title}");
                                }
                                catch (Exception e)
                                {
                                    WriteLog("Method-ProcessWebnLists, List-" + list.Title + ", Document Title - " + item.DisplayName + ", Error : " + e.Message);
                                    WriteLog("Method-ProcessWebnLists, StackTrace : " + e.StackTrace);
                                }
                            }
                            excelData.AppendFormat("{0},{1},ITEM,{2}", list.Title, (item.DisplayName).Replace(",", " "), groupNames);
                            excelData.AppendLine();
                        }
                    }
                    excelData.AppendLine();
                }
            }
        }
        catch (Exception ex)
        {
            WriteLog("Method-ProcessWebnLists, Error : " + ex.Message);
            WriteLog("Method-ProcessWebnLists, StackTrace : " + ex.StackTrace.ToString());
        }
    }

有人可以建议我在这方面还缺少什么,或者我需要做出哪些改变才能避免此错误?

这个过程花费了太多时间,所以我希望我的应用程序能够继续运行几个小时。

提前致谢!

1 个答案:

答案 0 :(得分:0)

getClientContext()是否位于foreach循环内?

我之前遇到此错误。 我添加了这个来解决我的问题。

public static void ExecuteQueryWithIncrementalRetry(this ClientContext context, int retryCount, int delay)
{
    int retryAttempts = 0;
    int backoffInterval = delay;
    if (retryCount <= 0)
        throw new ArgumentException("Provide a retry count greater than zero.");
   if (delay <= 0)
        throw new ArgumentException("Provide a delay greater than zero.");
   while (retryAttempts < retryCount)
    {
        try
        {
            context.ExecuteQuery();
            return;
        }
        catch (WebException wex)
        {
            var response = wex.Response as HttpWebResponse;
            if (response != null &amp;&amp; response.StatusCode == (HttpStatusCode)429)
            {
                Console.WriteLine(string.Format("CSOM request exceeded usage limits. Sleeping for {0} seconds before retrying.", backoffInterval));
                //Add delay.
                System.Threading.Thread.Sleep(backoffInterval);
                //Add to retry count and increase delay.
                retryAttempts++;
                backoffInterval = backoffInterval * 2;
            }
            else
            {
                throw;
            }
        }
    }
    throw new MaximumRetryAttemptedException(string.Format("Maximum retry attempts {0}, have been attempted.", retryCount));
}

基本上,这段代码会在执行另一个查询之前回退一定的时间间隔,以防止出现限制。

因此,不要使用ctx.ExecuteQuery()

此处进一步解释 https://docs.microsoft.com/en-us/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online