【问题标题】:Sorrow, Rage and Despair setting up Azure storage悲伤、愤怒和绝望设置 Azure 存储
【发布时间】:2023-03-23 05:25:01
【问题描述】:

我正在尝试在本地使用 Azure 存储。我有一个名为 ExpenseDataSource 的数据源类:

public class ExpenseDataSource
{
    private static CloudStorageAccount storageAccount;
    private ExpenseTableContext context;

    static ExpenseDataSource()
    {
        //CloudStorageAccount.SetConfigurationSettingPublisher(
        //    (configName, configSettingPublisher) =>
        //    {
        //        string connectionString = RoleEnvironment.GetConfigurationSettingValue(configName);
        //        configSettingPublisher(connectionString);
        //    }
        //);

        storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

        CloudTableClient.CreateTablesFromModel(typeof(ExpenseTableContext), storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
    }

    public ExpenseDataSource()
    {
        context = new ExpenseTableContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
        context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
    }

    public IEnumerable<ExpenseInfo> Select()
    {
        var results = from g in context.Expenses
                      where g.PartitionKey == "Expense"
                      select g;

        return results;
    }
    // ...
}

(我是 Azure 的新手,所以这个类在很多方面都不是最理想的。)

当我尝试创建ExpenseDataSource 类型的对象时,出现以下异常:

System.TypeInitializationException: The type initializer for 'WebRole1.ExpenseDataSource' threw an exception. ---> System.InvalidOperationException: SetConfigurationSettingPublisher needs to be called before FromConfigurationSetting can be used
   at Microsoft.WindowsAzure.CloudStorageAccount.FromConfigurationSetting(String settingName)
   at WebRole1.ExpenseDataSource..cctor() in [ ... ]
   --- End of inner exception stack trace ---
   at WebRole1.ExpenseDataSource..ctor()
   at WebRole1.ExpenseService.WebRole1.IExpenseService.GetExpenses() in [ ... ]

但是,这很奇怪,因为 SetConfiguationSettingPublisher 已经被调用:

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        DiagnosticMonitor.Start("DiagnosticsConnectionString");

        // For information on handling configuration changes
        // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
        RoleEnvironment.Changing += RoleEnvironmentChanging;

        CloudStorageAccount.SetConfigurationSettingPublisher(
            (configName, configSettingPublisher) =>
            {
                string connectionString = RoleEnvironment.GetConfigurationSettingValue(configName);
                configSettingPublisher(connectionString);
            }
        );

        return base.OnStart();
    }
    // ...
 }

当我开始调试时,我可以在这里打断点。

我在这里做错了什么?

更新:我想可能是我启动了 devfabric 和 ASP.NET localhost 故障,所以我将它们都杀了,启动了 dev fabic,然后启动了 ASP 项目。仍然没有运气 - 发生同样的错误。

更新 2:我将我的 OnStart() 更改为这个,但它仍然不起作用:

  public override bool OnStart()  
    {
        DiagnosticMonitor.Start("DiagnosticsConnectionString");

        // For information on handling configuration changes
        // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
        RoleEnvironment.Changing += RoleEnvironmentChanging;

        #region Setup CloudStorageAccount Configuration Setting Publisher

        // This code sets up a handler to update CloudStorageAccount instances when their corresponding
        // configuration settings change in the service configuration file.
        CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
        {
            // Provide the configSetter with the initial value
            configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

            RoleEnvironment.Changed += (sender, arg) =>
            {
                if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                    .Any((change) => (change.ConfigurationSettingName == configName)))
                {
                    // The corresponding configuration setting has changed, propagate the value
                    if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                    {
                        // In this case, the change to the storage account credentials in the
                        // service configuration is significant enough that the role needs to be
                        // recycled in order to use the latest settings. (for example, the 
                        // endpoint has changed)
                        RoleEnvironment.RequestRecycle();
                    }
                }
            };
        });
        #endregion

        return base.OnStart();
    }

更新 3:我尝试将“Setup CloudStorageAccount Configuration Setting Publisher”区域放在 ExpenseDataSource 静态初始化程序中,得到以下错误:

System.TypeInitializationException: The type initializer for 'WebRole1.ExpenseDataSource' threw an exception. ---> System.Runtime.InteropServices.SEHException: External component has thrown an exception.
   at RoleEnvironmentGetConfigurationSettingValueW(UInt16* , UInt16* , UInt32 , UInt32* )
   at Microsoft.WindowsAzure.ServiceRuntime.Internal.InteropRoleManager.GetConfigurationSetting(String name, String& ret)
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(String configurationSettingName)
   at WebRole1.ExpenseDataSource.<.cctor>b__0(String configName, Func`2 configSetter) in C:\Users\ODP\Documents\Visual Studio 2010\Projects\ExpenseCalc\WebRole1\ExpenseDataSource.cs:line 26
   at Microsoft.WindowsAzure.CloudStorageAccount.StorageAccountConfigurationSetting..ctor(String configurationSettingName)
   at Microsoft.WindowsAzure.CloudStorageAccount.FromConfigurationSetting(String settingName)
   at WebRole1.ExpenseDataSource..cctor() in C:\Users\ODP\Documents\Visual Studio 2010\Projects\ExpenseCalc\WebRole1\ExpenseDataSource.cs:line 47
   --- End of inner exception stack trace ---
   at WebRole1.ExpenseDataSource..ctor()
   at WebRole1.ExpenseService.WebRole1.IExpenseService.GetExpenses() in C:\Users\ODP\Documents\Visual Studio 2010\Projects\ExpenseCalc\WebRole1\ExpenseService.svc.cs:line 18

更新 3:按照 smarx 的建议,我更改了静态初始化程序:

    static ExpenseDataSource()
    {
        //storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
        storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));

        CloudTableClient.CreateTablesFromModel(typeof(ExpenseTableContext), storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
    }

这会导致以下错误:

System.TypeInitializationException: The type initializer for 'WebRole1.ExpenseDataSource' threw an exception. ---> System.Runtime.InteropServices.SEHException: External component has thrown an exception.
   at RoleEnvironmentGetConfigurationSettingValueW(UInt16* , UInt16* , UInt32 , UInt32* )
   at Microsoft.WindowsAzure.ServiceRuntime.Internal.InteropRoleManager.GetConfigurationSetting(String name, String& ret)
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(String configurationSettingName)
   at WebRole1.ExpenseDataSource..cctor() in C:\Users\ODP\Documents\Visual Studio 2010\Projects\ExpenseCalc\WebRole1\ExpenseDataSource.cs:line 20
   --- End of inner exception stack trace ---
   at WebRole1.ExpenseDataSource..ctor()
   at WebRole1.ExpenseService.WebRole1.IExpenseService.GetExpenses() in C:\Users\ODP\Documents\Visual Studio 2010\Projects\ExpenseCalc\WebRole1\ExpenseService.svc.cs:line 18

错误与上面略有不同。这是否与我实际上并未在开发结构中运行 ASP.NET 的想法有关?

呃。我开始怀念 Google App Engine 存储的简单 get()put() 界面。

【问题讨论】:

  • 断点的命中顺序是否正确?
  • 不确定。 OnStart() 断点只有在我第一次启动 Azure 开发结构时才会受到影响。 (即使我取消附加调试器,我想这不会杀死角色,因此以后不会调用 OnStart()。)我永远无法命中 WCF 服务或 @987654336 中设置的断点@.
  • 我有点困惑...您确定每次都启动云项目而不是 ASP.NET 项目吗? (您可以打开开发结构 UI 并验证您的应用程序是否正在运行。)听起来您可能正在开发结构 外部 运行 ASP.NET 项目。此外,您可以考虑使用 .Parse(RoleEnvironment.GetConfigurationSettingValue(...)) 而不是 .FromConfigurationSetting(...)。前者不需要设置发布者,但当您在运行时更改存储密钥时,它也不会自动修复问题。
  • @smarx 是的,听起来我可能在开发结构之外运行 ASP.NET 项目。我该如何验证/解决这个问题?
  • 我似乎记得一些关于静态构造函数和配置设置的事情。这与调用事物的顺序有关。只是为了看看是否是那个问题,我会尝试将当前静态的内容移至实际的构造函数(我知道这不是一个好的长期解决方案)

标签: azure azure-storage


【解决方案1】:

1) 确保在您的 WebRole 设置中配置了“DataConnectionString”。

  • 在您的解决方案资源管理器中 --> 在“Roles”文件夹下 --> 右键单击​​ |属性 --> 转到设置选项卡,然后单击“添加设置”。输入名称:“DataConnectionString”;类型:"ConnectionString";值:“UseDevelopmentStorage=true”(如果您想调试和使用本地存储)或者如果您计划迁移到 Azure,请输入您的存储帐户详细信息。

2) (在上面的代码中 - 删除 SetConfigurationSettingPublisher 的注释)。您的代码应如下所示:

CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});
var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

【讨论】:

    【解决方案2】:

    我能想到两个原因:

    1. 您使用的是 Azure SDK 1.3,必须在 Global.asax.cs Application_Start 中调用 SetConfigurationSettingPublisher;
    2. 您没有将 Startup 项目设置为 *.CloudService 项目。

    【讨论】:

      【解决方案3】:

      如果您仍然遇到问题,请尝试实际选择 Cloud Project 下的 Web 角色并从那里开始调试,当我遇到其他方法出现问题时,这对我有用。

      【讨论】:

        【解决方案4】:

        遇到同样的问题,我没有将 Azure 项目作为启动项目。

        正如 Muhammad Omar 在对该问题的评论中提到的那样,也请参阅此related question

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-29
          • 1970-01-01
          • 1970-01-01
          • 2012-01-14
          • 2014-09-30
          • 2011-07-17
          • 1970-01-01
          相关资源
          最近更新 更多