通过Azure函数中的CSOM从SharePoint Online访问TermCollection时的NULL术语

时间:2017-02-13 17:48:59

标签: c# azure sharepoint sharepoint-online azure-functions

我正在尝试使用Azure Functions公开REST API,它使用CSOM和C#从SharePoint Online中的特定术语集返回术语。

我绝对可以从控制台应用程序中调用这个完全相同的CSOM代码,并且能够成功遍历条款并输出到控制台。

但是,当从Azure功能主机调用以下代码时,总是在循环遍历TermCollectionIEnumerable<Term>时找到NULL术语对象的集合(我尝试在ClientContext.LoadQuery上使用TermSet.GetAllTerms(),并通过TermCollection属性加载TermSet.Terms

一旦迭代器遇到foreach中的一个术语(我也尝试过只是一个LINQ Select),它认为该项为NULL,因此调用它上面的属性会抛出NullReferenceException。我无法从控制台应用程序调用相同的代码重现行为 - 它只是按预期工作并检索每个Term对象。

为什么会在Azure Functions主机中发生这种情况,但在控制台应用中却不会发生?我该如何解决这个问题?

更新:有人将此问题标记为“什么是NRE”的副本。我知道NRE的发生方式和方式。这里的问题是为什么当从不同的主机调用SAME CODE时会发生这种情况?我知道抛出NRE的确切行,以及抛出它的对象 - 但不应该这样,因为这段代码可以从控制台应用程序中运行。从Azure Function主机调用时有什么区别?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Taxonomy;

namespace CsomTaxonomyHelper
{
    public class TermSearch
    {
        private readonly ClientContext ctx;
        public TermSearch(ClientContext context)
        {
            if (context == null)
                throw new ArgumentNullException(nameof(context));

            ctx = context;
        }

        public IEnumerable<TermViewModel> GetTerms(Guid termSetId)
        {
            var taxonomySession = TaxonomySession.GetTaxonomySession(ctx);
            var termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
            var termSet = termStore.GetTermSet(termSetId);

            //get flat list of terms, so we don't make recursive calls to SPO            
            var allTerms = ctx.LoadQuery(termSet.GetAllTerms().IncludeWithDefaultProperties());
            ctx.ExecuteQuery();

            return ToViewModel(allTerms);
        }

        static IEnumerable<TermViewModel> ToViewModel(IEnumerable<Term> allTerms)
        {
            var results = allTerms.Select(term => new TermViewModel
            {
                Id = term.Id, //BOOM! <-- within the context of an Azure Function the "allTerms" IEnumerable is a list of nulls
                Name = term.Name,
                ParentId = TryGetParentId(term)

            });

            return results;
        }

        static Guid? TryGetParentId(Term term)
        {
            try
            {
                if (term.Parent.IsPropertyAvailable("Id"))
                    return term.Parent.Id;
            }
            catch (ServerObjectNullReferenceException) { }
            return null;
        }
    }

    public class PasswordString
    {
        public SecureString SecurePassword { get; private set; }
        public PasswordString(string password)
        {
            SecurePassword = new SecureString();
            foreach (char c in password.ToCharArray())
            {
                SecurePassword.AppendChar(c);
            }
            SecurePassword.MakeReadOnly();
        }
    }
}

这是“run.csx”函数,调用上面的代码编译成DLL并放在Azure函数的Bin文件夹中:

#r "CsomTaxonomyHelper.dll"
#r "Newtonsoft.Json"

using System.Net;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Taxonomy;
using CsomTaxonomyHelper;
using Newtonsoft.Json;

static TraceWriter _log = null;
public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    _log = log;
    _log.Info("C# HTTP trigger function processed a request. Getting mmd terms from SPO...");


    var terms = GetFocusAreas();
    var result = JsonConvert.SerializeObject(terms);

    return req.CreateResponse(HttpStatusCode.OK, result);
}

static IEnumerable<TermViewModel> GetFocusAreas()
{
    string spSiteUrl = System.Environment.GetEnvironmentVariable("SPOSiteUrl", EnvironmentVariableTarget.Process);
    string userName = System.Environment.GetEnvironmentVariable("SPOUserName", EnvironmentVariableTarget.Process);
    string password = System.Environment.GetEnvironmentVariable("SPOPassword", EnvironmentVariableTarget.Process);

    var securePwd = new PasswordString(password).SecurePassword;

    using (var ctx = new ClientContext(spSiteUrl))
    {
        ctx.Credentials = new SharePointOnlineCredentials(userName, securePwd);
        ctx.ExecuteQuery();

        _log.Info("Logged into SPO service.");

        var search = new TermSearch(ctx);
        try
        {
            var result = search.GetTerms(new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
            return result;
        }
        catch (Exception ex)
        {
            _log.Error(ex.Message, ex);
            throw;
        }
    }
}

以下是本地调试器的屏幕截图,当使用Azure Functions CLI对其进行调试时(您可以看到它确实在集合中找到了10个项目,但所有项目都为空):

local debugger with Azure Function CLI

0 个答案:

没有答案