我在开发服务器上运行Azure时遇到了一些麻烦。我有一个Silverlight应用程序,我想连接到Azure,所以我从Web角色公开REST API。
这是我的服务类:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExpenseService
{
private ExpenseDataSource expenseData = new ExpenseDataSource();
[OperationContract]
[WebGet(UriTemplate="expenses", ResponseFormat=WebMessageFormat.Xml)]
public List<String> GetExpenses()
{
return expenseData.Select().ToList();
}
}
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);
}
// ...
}
错误是:
发现了SEHException
外部组件抛出了 异常。
我不确定我做错了什么。我正试图跟随这个tutorial。作者描述了需要为非Azure环境做一些不同的事情,比如NUnit测试。我是否需要在开发服务器上运行?我是否应该将此应用程序配置为使用真正的Azure存储,即使它正在我的机器上运行?
更新:如果我注释掉ExpenseDataSource
构造函数并只使用虚假数据,则该服务可以正常运行。
更新2 :@Maupertuis回答我无法从静态初始化程序设置存储帐户。但是,这直接来自MS Windows Azure代码示例:
public class GuestBookEntryDataSource
{
private static CloudStorageAccount storageAccount;
private GuestBookDataContext context;
static GuestBookEntryDataSource()
{
storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
CloudTableClient.CreateTablesFromModel(
typeof(GuestBookDataContext),
storageAccount.TableEndpoint.AbsoluteUri,
storageAccount.Credentials);
}
// ...
}
这可能有用吗?
答案 0 :(得分:1)
正如我之前所说(aaarg .. SO停机),您无法从静态构造函数中初始化您的Cloud Apps,因为静态构造函数将在类型初始化时调用。加载程序集时,但第一次使用类型时,不会发生类型初始化。
你应该使用create一个派生自RoleEntryPoint类的类。它将在角色启动时调用OnStart方法。
以下是一个示例:
public class WebRole: RoleEntryPoint
{
public override bool OnStart()
{
#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();
}
}
答案 1 :(得分:0)
您不应该从静态构造函数中调用SetConfigurationSettingPublisher。它不能保证完全运行,如果它运行,则无法保证何时运行。
如果确实如此,可以保证它将在Type初始化时执行。这是在第一次使用您的类ExpenseDataSource之前。如果不在应用程序中使用它,则也不会执行静态构造函数。由于必须在第一个请求之前调用SetConfigurationSettingPublisher(如果我记得很清楚),您将理解静态构造函数不是真正的方法。
您应该创建一个派生自RoleEntryPoint的类,Azure平台在启动时始终会调用其OnStart覆盖:
public class WebRole: RoleEntryPoint
{
public override bool OnStart()
{
#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();
}
}
这是一个例子,您可以将应用程序所需的初始化代码放在此处。