【发布时间】:2017-02-17 06:53:37
【问题描述】:
我正在尝试使用 Azure Functions 公开一个 REST API,它使用 CSOM 和 C# 从 SharePoint Online 中的特定术语集中返回术语。
我绝对可以从控制台应用程序和 Azure API 应用程序调用这个完全相同的 CSOM 代码,它能够循环遍历这些术语并成功输出到控制台或 HTTP 响应。
但是,当从 Azure Function 主机调用下面的代码时,它总是在循环通过 TermCollection 或 IEnumerable<Term> 时找到一个 NULL 术语对象的集合(我已经尝试在TermSet.GetAllTerms() 上使用ClientContext.LoadQuery,以及通过TermSet.Terms 属性加载TermCollection。
一旦迭代器在 foreach 中遇到一个术语(我也尝试过仅作为 LINQ 选择),它认为该项目为 NULL,因此对其调用属性会抛出 NullReferenceException。我无法从控制台应用程序或调用相同代码的 API 应用程序重现该行为 - 它只是在那里按预期工作并检索每个 Term 对象。
为什么从不同主机调用 SAME CODE 时会发生这种情况? 为什么这会发生在 Azure Functions 主机中,而不是在控制台应用或 Azure API 应用中?
从 Azure Function 主机调用时有什么区别??
我真的很想使用 Azure Functions 来获得消费定价优势,因此我不必在应用服务中托管它。
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;
}
}
}
项目.json:
{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.SharePointOnline.CSOM": "16.1.6112.1200"
}
}
}
}
这是本地调试器的屏幕截图,当使用 Azure Functions CLI 进行调试时(您可以看到它确实在集合中找到了 10 个项目,但所有项目都是空的):
【问题讨论】:
-
你能分享你的 project.json 吗?
-
{ "frameworks": { "net46":{ "dependencies": { "Microsoft.SharePointOnline.CSOM": "16.1.6112.1200" } } } }
-
我已经启动了 Fiddler,并比较了控制台应用程序客户端调用 SPO 与函数客户端调用 SPO 的响应。两者都返回了预期的数据。似乎问题出在 JSON 反序列化中?
-
这也是我的怀疑。这是否与您在自定义程序集中的参考相匹配?
-
我们可能因为私有程序集使用的加载上下文而遇到问题。只是要尝试一下...您可以尝试将该程序集移动到另一个文件夹(例如根目录下的 sharedbin)并使用该新路径(在本例中为#r“..\sharedbin\CsomTaxonomyHelper.dll”)引用它吗?
标签: azure sharepoint sharepoint-online azure-functions