0

在解析使用 SAS 令牌的连接字符串时,我很难让 Microsoft.Azure.Cosmos.Table 自动初始化 SecondaryUri。

因此,我最终在连接字符串中明确指定了 TableSecondaryEndpoint,这有效,但我无法查询辅助节点,因为 SDK 在尝试请求之前就抛出了异常。

在我的测试中,我发现这是 Microsoft.WindowsAzure.Storage.Table 8.7.0 中不存在的回归(Microsoft.Azure.Cosmos.Table 1.0.6 的基础)

对此,专家意见非常欢迎。谢谢你。

此异常的项目代码在这里(也在下面复制): https ://github.com/golfalot/SOshowAzureTableBug

详细说明这里提出的 SecondaryUri 初始化问题的附带问题: https ://github.com/Azure/azure-cosmos-table-dotnet/issues/36

using System;
using System.Collections.Generic;

using LEGACY_STORAGE = Microsoft.WindowsAzure.Storage;
using LEGACY_RETRY = Microsoft.WindowsAzure.Storage.RetryPolicies;
using LEGACY_TABLE = Microsoft.WindowsAzure.Storage.Table; //8.7.0 because this is the base for 1.0.6

using NEWEST_TABLE = Microsoft.Azure.Cosmos.Table; // version 1.0.6
using Microsoft.Azure.Cosmos.Table; // had to add this to get access CreateCloudTableClient extension method

using System.Diagnostics;

namespace SOshowAzureTableBug
{
    class Program
    {
        // the SAS token is immaterial in reproducing the problem
        const string connectionTableSAS = "TableSecondaryEndpoint=http://127.0.0.1:10002/devstoreaccount1-secondary;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;SharedAccessSignature=immaterial";
        static void Main(string[] args)
        {

            /* Legacy Table SDK */
            var storageAccountLegacy = LEGACY_STORAGE.CloudStorageAccount.Parse(connectionTableSAS);
            var tableClientLegacy = storageAccountLegacy.CreateCloudTableClient();
            Debug.Assert(tableClientLegacy.StorageUri.SecondaryUri != null); // demonstrate SecondaryUri initialised

            var tableRequestOptionsLegacy = new LEGACY_TABLE.TableRequestOptions () { LocationMode = LEGACY_RETRY.LocationMode.SecondaryOnly };
            tableClientLegacy.DefaultRequestOptions = tableRequestOptionsLegacy;

            var tableLegacy = tableClientLegacy.GetTableReference("foo"); // don't need table to exist to show the issue
            var retrieveOperation = LEGACY_TABLE.TableOperation.Retrieve(string.Empty, string.Empty, new List<string>() { "bar" });

            var tableResult = tableLegacy.Execute(retrieveOperation);
            Console.WriteLine("Legacy PASS");


            /* Newset Table SDK */
            var storageAccountNewest = NEWEST_TABLE.CloudStorageAccount.Parse(connectionTableSAS);
            var tableClientNewest = storageAccountNewest.CreateCloudTableClient(new TableClientConfiguration());
            Debug.Assert(tableClientNewest.StorageUri.SecondaryUri != null); // demonstrate SecondaryUri initialised

            var tableRequestOptionsNewest = new NEWEST_TABLE.TableRequestOptions() { LocationMode = NEWEST_TABLE.LocationMode.SecondaryOnly };
            tableClientNewest.DefaultRequestOptions = tableRequestOptionsNewest;

            var tableNewset = tableClientNewest.GetTableReference("foo"); // don't need table to exist to show the issue
            var retrieveOperationNewset = NEWEST_TABLE.TableOperation.Retrieve(string.Empty, string.Empty, new List<string>() { "bar" });

            /* throws Microsoft.Azure.Cosmos.Table.StorageException
             * Exception thrown while initializing request: This operation can only be executed against the primary storage location
             */
            var tableResultNewset = tableNewset.Execute(retrieveOperationNewset);

            Console.WriteLine("Press any key to exit");
            Console.Read();
        }
    }
}

4

1 回答 1

2

我相信您遇到了 SDK 的错误。

当我尝试以下代码时,我收到与您相同的错误:

        var account = CloudStorageAccount.Parse(connectionString);

        var requestOptions = new TableRequestOptions()
        {
            LocationMode = LocationMode.SecondaryOnly
        };
        var client = account.CreateCloudTableClient();
        client.DefaultRequestOptions = requestOptions;
        var table = client.GetTableReference("myTable");
        var op = TableOperation.Retrieve("", "");
        var result1 = table.Execute(op);

我反编译了库代码,找到了罪魁祸首源代码:

if (commandLocationMode == CommandLocationMode.PrimaryOnly)
                {
                    if (restCMD.LocationMode == LocationMode.SecondaryOnly)
                    {
                        throw new InvalidOperationException("This operation can only be executed against the primary storage location.");//This is the error that gets thrown.
                    }
                    Logger.LogInformational(executionState.OperationContext, "This operation can only be executed against the primary storage location.", Array.Empty<object>());
                    executionState.CurrentLocation = StorageLocation.Primary;
                    restCMD.LocationMode = LocationMode.PrimaryOnly;
                }

但是,如果我没有DefaultRequestOptions在客户端级别设置并在下面的Execute方法中指定它,我不会收到错误,但这是因为主要端点被命中而不是次要端点(我在 Fiddler 中检查过)。

        var account = CloudStorageAccount.Parse(connectionString);

        var requestOptions = new TableRequestOptions()
        {
            LocationMode = LocationMode.SecondaryOnly
        };
        var client = account.CreateCloudTableClient();
        var table = client.GetTableReference("myTable");
        var op = TableOperation.Retrieve("", "");
        var result1 = table.Execute(op, requestOptions);

解决方法

如果您的目标是从辅助位置查询实体,那么您可以使用如下所示ExecuteQuery的方法。CloudTable这有效(再次,我检查了 Fiddler)。

        var account = CloudStorageAccount.Parse(connectionString);

        var requestOptions = new TableRequestOptions()
        {
            LocationMode = LocationMode.SecondaryOnly
        };
        var client = account.CreateCloudTableClient();
        client.DefaultRequestOptions = requestOptions;
        var table = client.GetTableReference("myTable");
        TableQuery query = new TableQuery();
        var result = table.ExecuteQuery(query).ToList();
于 2020-02-24T16:12:12.767 回答