通过Azure功能中的CSOM从SharePoint Online访问TermCollection时获取NULL术语

时间:2017-02-16 17:40:19

标签: azure sharepoint sharepoint-online azure-functions

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

我绝对可以从控制台应用程序和Azure API应用程序中调用这个完全相同的CSOM代码,并且它能够成功地遍历条件并输出到控制台或HTTP响应。

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

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

为什么在从不同的主机调用SAME CODE时会发生这种情况? 为什么会发生在Azure Functions主机中,而不是在Console应用程序或Azure API应用程序中?

从Azure功能主机调用时有什么区别??

我真的很想使用Azure功能来获得消费定价优惠,因此我不必在App Service中托管它。

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();
        }
    }
}

这是&#34; run.csx&#34;函数,调用上面的代码,该代码已编译成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;
        }
    }
}

Project.json:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "Microsoft.SharePointOnline.CSOM": "16.1.6112.1200"
      }
    }
  }
}

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

local debugger with Azure Function CLI

1 个答案:

答案 0 :(得分:0)

enter image description here

不是解决方案,而是添加到对话中 - 我能够使用PnP-PowerShell(2017年2月)进行测试。条款刚刚添加。

SPO,CSOM和PnP-PowerShell。

将PnP-PowerShell安装到PowerShell功能:

Drag and drop from windows to modules subfolder