Getting NULL terms when accesing TermCollection from SharePoint Online via CSOM in an Azure Function

百般思念 提交于 2019-12-12 09:26:49

问题


I am trying to expose a REST API using Azure Functions which returns terms from a specific termset in SharePoint Online using CSOM and C#.

I can definitely invoke this exact same CSOM code from a console app and from an Azure API app and it is able to loop through the terms and output to console or the HTTP response successfully.

However, when the code below is invoked from the Azure Function host, it ALWAYS find a collection of NULL term objects, when looping through the TermCollection or the IEnumerable<Term> (I’ve tried by using ClientContext.LoadQuery on TermSet.GetAllTerms(), as well as by just loading the TermCollection via the TermSet.Terms property).

As soon as the iterator hits a term in the foreach (which I’ve also tried as just a LINQ Select), it thinks that the item is NULL, so calling properties on it throws the NullReferenceException. I cannot reproduce the behavior from the console app or from the API app calling into the same code - it just works as expected there and retrieves each Term object.

Why is this happening when SAME CODE is invoked from different hosts?? Why would this happen in the Azure Functions host, but not in Console app or the Azure API app?

What is the difference when invoked from an Azure Function host??

I would really like to use Azure Functions for the consumption pricing benefits, so I don't have to host this in an 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();
        }
    }
}

Here's the "run.csx" function, invoking the code above which has been compiled into a DLL and placed in the Bin folder of the Azure Function:

#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"
      }
    }
  }
}

Here's the screenshot of the local debugger, when using the Azure Functions CLI to debug this (you can see that it did find 10 items in the collection, but all items are null):


回答1:


Not the solution, but adding to the conversation - I was able to test with PnP-PowerShell (2017-Feb). Terms were just added.

SPO, CSOM and PnP-PowerShell.

Installing PnP-PowerShell to a PowerShell function:



来源:https://stackoverflow.com/questions/42281084/getting-null-terms-when-accesing-termcollection-from-sharepoint-online-via-csom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!