Sorrow,Rage和Despair设置Azure存储

时间:2010-10-11 23:27:05

标签: azure azure-storage

我正在尝试在本地使用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();
    }
    // ...
 }

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

我在这里做错了什么?

更新:我想也许我已经启动了dev结构和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 :我尝试将“设置CloudStorageAccount配置设置发布器”区域放在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()界面。

4 个答案:

答案 0 :(得分:2)

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

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

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

CloudStorageAccount.SetConfigurationSettingPublisher((configName,configSetter)=&gt;
            {
                 configSetter(RoleEnvironment.GetConfigurationSettingValue(CONFIGNAME));
            });
            var storageAccount = CloudStorageAccount.FromConfigurationSetting(“DataConnectionString”);

答案 1 :(得分:1)

我可以想到两个原因:

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

正如穆罕默德·奥马尔在对这个问题的评论中提到的那样,也请看related question