【问题标题】:Azure Function error in deployment using identity management使用身份管理进行部署时出现 Azure Function 错误
【发布时间】:2021-01-25 13:28:16
【问题描述】:

我创建了一个通过一些 API 运行的 Azure 函数,所有这些都按预期工作。但是,一旦我添加了一个异步方法来使用身份管理访问数据库。我开始收到以下错误。

Executed 'AzureFunction1' (Failed, Id=215dbf92-b461-4576-94a8-3fe917d67270, Duration=2470ms)Object reference not set to an instance of an object.

我尝试将连接方法更改为异步,以便可以使用await,但我认为可能存在同步问题。然后我真的不确定它指的是哪个变量。我很难弄清楚。

我试图通过放置以下信息从错误中获取更多信息,但无论如何我没有得到太多回报。

catch (Exception e)
            {
                var error = $"My error text";
logger.LogError(error + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace +
                                e.InnerException != null ? Environment.NewLine + Environment.NewLine + 
                                e.InnerException.Message + Environment.NewLine + e.InnerException.StackTrace : "");
            }

这是我添加到访问数据库的方法,我在稍后的函数中使用它来将 int 添加到一些 JSON 中。 (之前用 0 测试过)。在本地版本中一切似乎都运行良好,只有在我在部署中测试它时才会出错

public async Task<int> GetCountAsync(Record record)
        {

            try
            {
                //get access token from managed identity
                var azureServiceTokenProvider = new AzureServiceTokenProvider();

                var accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/");
  
                var connectionString = "Server = tcp:***,Port; Initial Catalog = ***";

                using SqlConnection conn = new SqlConnection(connectionString)
                {
                    AccessToken = accessToken
                };
                conn.Open();
                var state = conn.State;
                using SqlCommand comm = new SqlCommand();
                var withBlock = comm;
                withBlock.Connection = conn;
                withBlock.CommandText = $"SELECT COUNT(ID)AS 'count'\n";
                logger.LogInformation("Query: " + withBlock.CommandText);
                var reader = comm.ExecuteReader();

                reader.Read();

                int count = reader.GetInt32("count");
                logger.LogInformation("Count = " + count.ToString());
                return count;
            }
            catch (Exception e)
            {
                var error = $"Error retrieving the count for this record: {record.ID}";
                logger.LogError(error + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace +
                                e.InnerException != null ? Environment.NewLine + Environment.NewLine + e.InnerException.Message + Environment.NewLine + e.StackTrace : "");
                throw new Exception(error, e);
            }
        }

根据我的输出,它一直在工作,直到我记录查询然后它抛出一个 500 Internal Server Error 和我在开始时显示的错误。

【问题讨论】:

  • 您应该添加更多日志并查看可能导致此 null ref 错误的灰色代码。

标签: c# async-await azure-functions azure-managed-identity


【解决方案1】:

在 C#8 或更高版本中,您可以使用如下语法:

using SqlConnection conn = new SqlConnection(connectionString);

但它应该以“;”结尾。

由于您使用了“{}” 您在创建后立即释放了连接。

来自 MS 文档: public override int GetInt32 (int ordinal); ordinal 是 Int32 从零开始的列序号。

所以不是

count = reader.GetInt32("count");

尝试使用

count = Convert.ToInt32(reader["count"]);

所以你的代码应该是这样的:

using SqlConnection conn = new SqlConnection(connectionString)
{
                    AccessToken = accessToken
             
                var state = conn.State;
                using SqlCommand comm = new SqlCommand();
                var withBlock = comm;
                withBlock.Connection = conn;
                withBlock.CommandText = $"SELECT COUNT(ID)AS 'count'\n";
                logger.LogInformation("Query: " + withBlock.CommandText);
                conn.Open();
                var reader = comm.ExecuteReader();
               var count=0;
               if (reader.HasRows)
                {
                 if reader.Read()
                  {
               count = Convert.ToInt32(reader["count"]);
                 reader.Close();
                  }
             }
            logger.LogInformation("Count = " + count.ToString());
            return count;
}

【讨论】:

  • 不会立即处理。它基于 using 声明:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
  • 在我的回答中看到一些新的解释。
  • 我相信你读错了 OP 的代码。在 using 声明后面实际上有一个 ; (它只低了 3 行,因为 OP 还使用了一个对象初始化器)。 var myDisposable = new MyDisposable(){}(后面没有;,所以它会立即处理)不是有效的语法,所以不会编译。
  • 也许你是对的。但我更喜欢显式语法。还有另一个错误
【解决方案2】:

感谢所有反馈的家伙。原来我的错误是由于缺乏权限引起的。我使用具有写入权限的 DB 用户设置了该功能。没想到读写权限是分开的。

根据得到的提要,我调整了我的代码以使其更具可读性。这是最终结果:

public async Task<int> GetCountAsync(Record record)
        {
            var count = -1;
            try
            {
                //get access token from managed identity
                var azureServiceTokenProvider = new AzureServiceTokenProvider();

                var accessToken = await
                    azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/");
                logger.LogInformation(accessToken);

                var connectionString = "Server = tcp:***,Port; Initial Catalog = ***";

                var query = $"SELECT COUNT(ID)AS 'count'\n";
                logger.LogInformation("Query: " + query);

                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    conn.AccessToken = accessToken;
                    conn.Open();
                    var state = conn.State;
                    using var comm = new SqlCommand(query, conn);
                    var reader = comm.ExecuteReader();

                    if (reader.HasRows)
                    {
                        if (reader.Read())
                        {
                            count = reader.GetInt32("count");
                            reader.Close();
                            logger.LogInformation("Count = " + count.ToString());
                        }
                    }
                }
                return count;
            }
            catch (Exception e)
            {
                var error = $"Error retrieving the count for record: {record.ID}";
                logger.LogError(error + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace +
                                e.InnerException == null ? Environment.NewLine + e.InnerException.Message + Environment.NewLine + e.InnerException.StackTrace : "");
                throw new Exception(error, e);
            }
        }

我能够使用以下查询在数据库中设置权限

CREATE USER "AzureFunction1" FROM EXTERNAL PROVIDER;
ALTER ROLE db_datawriter ADD MEMBER "AzureFunction1";
ALTER ROLE db_datareader ADD MEMBER "AzureFunction1";

【讨论】:

    猜你喜欢
    • 2015-12-16
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    相关资源
    最近更新 更多