簡體   English   中英

Azure Function 和 SharePoint webhook:未從 Z97F02F6993B93736DFEZ0D 列表中獲取更改

[英]Azure Function and SharePoint webhook: not getting changes from SharePoint list

我正在使用幾個 Azure 函數和 SharePoint webhook。

第一個 function 用於將消息從 SharePoint webhook 保存到隊列(Azure 存儲隊列)。 這是function內容:

    [FunctionName("QueueFunction")]
    public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
         log.Info($"Webhook was triggered!");

        // Grab the validationToken URL parameter
        string validationToken = req.GetQueryNameValuePairs()
            .FirstOrDefault(q => string.Compare(q.Key, "validationtoken", true) == 0)
            .Value;

        // If a validation token is present, we need to respond within 5 seconds by  
        // returning the given validation token. This only happens when a new 
        // web hook is being added
        if (validationToken != null)
        {
            log.Info($"Validation token {validationToken} received");
            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Content = new StringContent(validationToken);
            return response;
        }

        log.Info($"SharePoint triggered our webhook...great :-)");
        var content = await req.Content.ReadAsStringAsync();
        log.Info($"Received following payload: {content}");

        var notifications = JsonConvert.DeserializeObject<ResponseModel<NotificationModel>>(content).Value;
        log.Info($"Found {notifications.Count} notifications");

        if (notifications.Count > 0)
        {
            // get the cloud storage account
            string queueName = "MYQUEUE";
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
            CloudQueue queue = queueClient.GetQueueReference(queueName);
            await queue.CreateIfNotExistsAsync();

            // store each notification as a queue item
            foreach (var notification in notifications)
            {
                string message = JsonConvert.SerializeObject(notification);
                log.Info($"Adding to {queueName}: {message}");
                await queue.AddMessageAsync(new CloudQueueMessage(message));
                log.Info($"added.");
            }

        // if we get here we assume the request was well received
        return new HttpResponseMessage(HttpStatusCode.OK);
    }

隊列中的消息已正確添加。

然后我有另一個由隊列觸發的 function 。 這是 function 的代碼:

[FunctionName("OCRFunction")]
    public static void Run([QueueTrigger("MYQUEUE", Connection = "QueueConn")]string myQueueItem, TraceWriter log)
    {
        log.Info($"C# Queue trigger function processed: {myQueueItem}");
        string siteUrl = "https://MYSHAREPOINT.sharepoint.com/sites/MYSITE";
        log.Info($"Processing notifications...");
        string json = myQueueItem;
        var data = (JObject)JsonConvert.DeserializeObject(json);
        string notificationResource = data["resource"].Value<string>();
        
        ClientContext SPClientContext = LoginSharePoint(siteUrl);
        log.Info($"Logged in SharePoint");
        GetChanges(SPClientContext, notificationResource, log);
       
    }

    public static ClientContext LoginSharePoint(string BaseUrl)
    {
        // Login using UserOnly Credentials (User Name and User PW)
        ClientContext cntReturn;

        string myUserName = config["spUN"];
        string myPassword = config["spPWD"];

        SecureString securePassword = new SecureString();
        foreach (char oneChar in myPassword) securePassword.AppendChar(oneChar);
        SharePointOnlineCredentials myCredentials = new SharePointOnlineCredentials(myUserName, securePassword);

        cntReturn = new ClientContext(BaseUrl);
        cntReturn.Credentials = myCredentials;

        return cntReturn;
    }

    static void GetChanges(ClientContext SPClientContext, string ListId, TraceWriter log)
    {
        Web spWeb = SPClientContext.Web;
        List myList = spWeb.Lists.GetByTitle("MY LIST");
        SPClientContext.Load(myList);
        SPClientContext.ExecuteQuery();

        ChangeQuery myChangeQuery = GetChangeQueryNew(ListId);

        var allChanges = myList.GetChanges(myChangeQuery);
        SPClientContext.Load(allChanges);
        SPClientContext.ExecuteQuery();

        log.Info($"---- Changes found : " + allChanges.Count());
        foreach (Change oneChange in allChanges)
        {
            if (oneChange is ChangeItem)
            {
                int myItemId = (oneChange as ChangeItem).ItemId;

                log.Info($"---- Changed ItemId : " + myItemId);
                ListItem myItem = myList.GetItemById(myItemId);
                Microsoft.SharePoint.Client.File myFile = myItem.File;
                ClientResult<System.IO.Stream> myFileStream = myFile.OpenBinaryStream();
                SPClientContext.Load(myFile);
                SPClientContext.ExecuteQuery();

                byte[] myFileBytes = ConvertStreamToByteArray(myFileStream);
                [...] SOME CODE HERE [...]
                myItem["OCRText"] = myText;
                myItem.Update();
                SPClientContext.ExecuteQuery();
                log.Info($"---- Text Analyze OCR added to SharePoint Item");
            }
        }
    }

    public static ChangeQuery GetChangeQueryNew(string ListId)
    {
        ChangeToken lastChangeToken = new ChangeToken();
        lastChangeToken.StringValue = string.Format("1;3;{0};{1};-1", ListId, DateTime.Now.AddMinutes(-1).ToUniversalTime().Ticks.ToString());
        ChangeToken newChangeToken = new ChangeToken();
        newChangeToken.StringValue = string.Format("1;3;{0};{1};-1", ListId, DateTime.Now.ToUniversalTime().Ticks.ToString());
        ChangeQuery myChangeQuery = new ChangeQuery(false, false);
        myChangeQuery.Item = true;  // Get only Item changes
        myChangeQuery.Add = true;   // Get only the new Items
        myChangeQuery.ChangeTokenStart = lastChangeToken;
        myChangeQuery.ChangeTokenEnd = newChangeToken;

        return myChangeQuery;
    }

    public static Byte[] ConvertStreamToByteArray(ClientResult<System.IO.Stream> myFileStream)
    {
        Byte[] bytReturn = null;

        using (System.IO.MemoryStream myFileMemoryStream = new System.IO.MemoryStream())
        {
            if (myFileStream != null)
            {
                myFileStream.Value.CopyTo(myFileMemoryStream);
                bytReturn = myFileMemoryStream.ToArray();
            }
        }

        return bytReturn;
    }

    public static async Task<TextAnalyzeOCRResult> GetAzureTextAnalyzeOCR(byte[] myFileBytes)
    {
        TextAnalyzeOCRResult resultReturn = new TextAnalyzeOCRResult();

        HttpClient client = new HttpClient();

        client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "XXXXXXXXXXXXXXXXXXXX");
        string requestParameters = "language=unk&detectOrientation=true";

        /* OCR API */
        string uri = "https://MYOCRSERVICE.cognitiveservices.azure.com/vision/v3.0/ocr" + "?" + requestParameters;

        string contentString = string.Empty;

        HttpResponseMessage response;

        using (ByteArrayContent content = new ByteArrayContent(myFileBytes))
        {
            content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

            response = await client.PostAsync(uri, content);

            contentString = await response.Content.ReadAsStringAsync();

            resultReturn = JsonConvert.DeserializeObject<TextAnalyzeOCRResult>(contentString);
            return resultReturn;
        }
    }

在當前使用兩個函數的方法之前,我使用單個 function 管理通知並執行一些代碼來更新 SharePoint 列表中的字段。 當我收到來自 SharePoint 的許多通知時,此方法出現了一些問題,因此我決定按照 Microsoft 文檔中的建議使用隊列。 此解決方案在收到單個通知時運行良好,並且我的 SharePoint 列表項已毫無問題地更新。

為了避免多個通知的問題,我決定拆分功能,一個在隊列中注冊通知,另一個執行一些操作並更新 SharePoint 字段。 第一個 function QueueFunction工作正常,第二個觸發正確,但即使我只添加一個項目,它也沒有從 SharePoint 列表中獲得更改。 我試圖檢查GetChanges代碼以找出為什么它總是不返回任何更改,但代碼與我只有一個 function 時使用的代碼相同,所以我不明白為什么行為會改變。

我的方法有什么問題? 我可以做些什么來糾正第二個 function?

根據評論,將解決方案總結如下,供其他社區參考:

Use a function to save the message in a queue and then call an azure web job, the problem was caused by the the running time of the function may exceed 5 minutes.

順便說一句,azure 函數(有消費計划)的默認超時時間是 5 分鍾,我們可以在這個頁面上看到不同計划的所有默認超時時間(也如下圖所示)。

在此處輸入圖像描述

如果我們想要更長的超時時間,我們可以在函數的host.json中設置functionTimeout屬性(但不能超過Maximum timeout)。 或者我們也可以為 function 應用程序使用更高的計划,例如高級計划和應用服務計划。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM