【问题标题】:Precompiled Azure Function throwing error on HttpClientExtensions.SetBearerToken use, CSX doesn't使用 HttpClientExtensions.SetBearerToken 时预编译的 Azure 函数抛出错误,CSX 没有
【发布时间】:2017-09-08 02:11:24
【问题描述】:

首先,我使用以下博客文章来帮助我将 CSX Azure 函数转换为预编译的类库 - https://blogs.msdn.microsoft.com/appserviceteam/2017/03/16/publishing-a-net-class-library-as-a-function-app/?utm_source=Direct

我认为它应该可以工作,但作为预编译函数,它会在 SetBearerToken(位于 System.Net.Http.HttpClientExtensions 中)上引发“未找到方法”异常,但它没有在 CSX 版本中找到此方法没有任何问题。这是完整的错误:

Exception while executing function: Functions.notifications-queue-trigger Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Functions.notifications-queue-trigger ---> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ---> System.MissingMethodException : Method not found: 'Void System.Net.Http.HttpClientExtensions.SetBearerToken(System.Net.Http.HttpClient, System.String)'.

预编译函数和 CSX 脚本之间的代码几乎相同(显然需要的差异除外)。

我在这里缺少什么?为什么它在作为 CSX 脚本编写时没有问题时在预编译版本中的 System.Net.Http.HttpClientExtensions 中为 SetBearerToken 抛出“方法未找到”异常?任何帮助表示赞赏。

这是我作为 CSX 脚本的功能,它有效:

#r "IdentityModel.dll"
#r "Sorbet.DataTransferObjects.dll"
#r "Newtonsoft.Json"

using System;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;

using IdentityModel.Client;
using Newtonsoft.Json;
using Sorbet.DataTransferObjects;

public static void Run(NotificationDto myQueueItem, TraceWriter log)
{
    log.Info($"C# ServiceBus queue trigger function processed message");
    TokenResponse idToken;
    using (var tokenClient = new TokenClient("https://myidserver", "myclientid", "myclientsecret"))
    {
        var response = tokenClient.RequestClientCredentialsAsync("myscope");
        idToken = response.Result;
        log.Info($"Access token retrieved : {idToken.AccessToken}");
    }

    using (var apiClient = new HttpClient())
    {
        var apiUrl = "https://myapiurl/";
        var endpoint = "myendpoint";
        string data = JsonConvert.SerializeObject(myQueueItem);
        log.Info($"Hitting API...");

        apiClient.SetBearerToken(idToken.AccessToken);
        var response = apiClient.PostAsync($"{apiUrl}{endpoint}", new StringContent(data, Encoding.UTF8, "application/json")).Result;
    }
}

这是我作为 C# 类的函数,这会在 SetBearerToken 调用中引发上述错误:

using System;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;

using IdentityModel.Client;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
using Sorbet.DataTransferObjects;

namespace FunctionsClassLibTest
{
    public class NotificationQueueTrigger
    {
        public static void Run(NotificationDto myQueueItem, TraceWriter log)
        {
            log.Info($"C# ServiceBus queue trigger function processed message");
            TokenResponse idToken;
            using (var tokenClient = new TokenClient("https://myidserver", "myclientid", "myclientsecret"))
            {
                var response = tokenClient.RequestClientCredentialsAsync("myscope");
                idToken = response.Result;
                log.Info($"Access token retrieved : {idToken.AccessToken}");
            }

            using (var apiClient = new HttpClient())
            {
                var apiUrl = "https://myapiurl";
                var endpoint = "myendpoint";
                string data = JsonConvert.SerializeObject(myQueueItem);
                log.Info($"Hitting API...");

                apiClient.SetBearerToken(idToken.AccessToken);
                var response = apiClient.PostAsync($"{apiUrl}{endpoint}", new StringContent(data, Encoding.UTF8, "application/json")).Result;
            }
        }
    }
}

这是我的预编译函数的function.json 文件(CSX 几乎相同,但它只有绑定部分)

{
  "scriptFile": "..\\bin\\FunctionsClassLibTest.dll",
  "entryPoint": "FunctionsClassLibTest.NotificationQueueTrigger.Run",
  "bindings": [
    {
      "name": "myQueueItem",
      "type": "serviceBusTrigger",
      "direction": "in",
      "queueName": "notifications",
      "connection": "dev-bus",
      "accessRights": "manage"
    }
  ],
  "disabled": false
}

【问题讨论】:

  • 看起来IdentityModel.dll 没有正确加载。你如何引用它?附带说明一下,尝试将您的代码示例最小化到重现问题所需的最少数量。
  • 谢谢米哈伊尔。这次我只发布了完整的代码,因为这似乎是一个奇怪的问题,其中一个可能是微小的问题! IdentityModel 也是我的第一个想法,但它似乎超越了 IdentityModel 的东西,这就是第一个 using 语句中的东西,它进入我的 ID 服务器并获取我的令牌。它在第二个 using 语句中对 SetBearerToken 的调用失败,这是 System.Net.Http.HttpClientExtensions 中带有 MissingMethodException 的 HttpClient 的扩展方法
  • 啊,是的,我的错 - 它确实在抱怨 HttpClientExtensions。你明白我为什么要一个更小的例子;)你仍然处于尝试从函数中删除一些部分(例如 IdentityServer)并查看这是否会改变结果的最佳位置 - 并相应地调整你的问题。
  • 这是个好主意。我将尝试将功能降低到绝对最小值,看看这是否有助于我进一步发展。谢谢:)
  • 我将其缩减为仅调用 SetBearerToken 并且它仍然抛出相同的错误。认为我可能也应该在 MS 论坛上发帖,因为我认为它可能与代码无关。

标签: c# azure identityserver3 azure-functions


【解决方案1】:

好的,所以我已经找到了解决方案。问题是我一开始认为它可能就在 IdentityModel 库中。我被抛出错误的命名空间抛出,这让我在几个小时内疯狂追逐。事实上,HttpClient 的扩展是在 IdentityModel 库中定义的。

确切地知道问题出在哪里,我查看了扩展,只是将 apiClient.SetBearerToken("myBearerToken"); 行替换为该扩展方法 apiClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "myBearerToken"); 中使用的代码,这现在可以在我的预编译函数中使用。

这并没有回答 为什么 它在 CSX 中工作而不是在预编译函数中工作的问题。如果有人对为什么会这样有任何想法,我真的很想知道!我知道 IdentityModel 库的导入没有问题,因为我使用它从我的 ID 服务器获取令牌并且工作正常,因此它必须是特定于扩展方法的东西。有问题的扩展方法可以在这里看到 - https://github.com/IdentityModel/IdentityModel/blob/master/source/IdentityModel.Shared/Client/HttpClientExtensions.cs

【讨论】:

  • 从预编译函数中查看您引用的 System.Net.Http 版本会很有趣。我们可能正在处理一些类型不匹配,导致在运行时无法绑定到这些方法。
  • 这是来自我的packages.config 的元素。只是我创建项目时安装的版本<package id="System.Net.Http" version="4.3.1" targetFramework="net461" />
  • 抱歉,我实际上只是注意到 System.Net.Http 包是作为 IdentityModel 包的依赖项安装的,因此它在项目创建时并不存在。
猜你喜欢
  • 2017-05-28
  • 2018-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-23
  • 2020-01-04
相关资源
最近更新 更多