我正在尝试在本地使用 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 的新手,所以这个类在很多方面可能不是最理想的。)
当我尝试创建 type 的对象时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 fabric 和 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()
。