2

我有一个带有 Azure 云服务项目和一个 webrole 的 .NET Web 解决方案。我将它部署到东海岸西海岸数据/计算中心以进行故障转移,并被要求使用 Powershell MSBuild 和 Jenkins 自动执行部署。

问题是我需要在打包和发布到每个部署之前更改 Web.config 中的 Sql Azure 数据库连接字符串。看起来很简单。

我了解 webrole 属性设置选项卡允许您使用“字符串”或“连接字符串”类型向每个部署添加自定义配置属性,但看起来“连接字符串”选项仅适用于 Blob、表或队列存储. 如果我使用“字符串”并给它一个 Sql Azure 连接字符串类型,它会将其写为键/值对,而实体框架和成员资格提供程序找不到它。

有没有办法添加指向 Sql Azure 的每个部署的连接字符串设置?

谢谢,

大卫

4

2 回答 2

2

埃里克的解决方案是完全有效的,我找到了另一种解决问题的方法,所以我想我会回来把它放在这里,因为我很难找到答案。

诀窍是让实体框架和任何提供程序(如 asp.net Membership/profile/session 等)直接从 Azure 服务配置而不是站点 web.config 文件中读取连接字符串。

对于提供程序,我能够创建继承 System.Web.Providers.DefaultMembershipProvider 类的类并覆盖 Initialize() 方法,然后我使用我编写的帮助程序类来使用 RoleEnvironment.GetConfigurationSettingValue(settingName); 检索连接字符串;调用,它从 Azure 服务配置中读取。

然后我告诉 Membership 提供者使用我的类而不是 DefaultMembershipProvider。这是代码:

网络配置:

<membership defaultProvider="AzureMembershipProvider">
  <providers>
    <add name="AzureMembershipProvider" type="clientspace.ServiceConfig.AzureMembershipProvider" connectionStringName="ClientspaceDbContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
  </providers>

注意自定义提供程序“AzuremembershipProvider”

AzuremembershipProvider 类:

public class AzureMembershipProvider : System.Web.Providers.DefaultMembershipProvider
{
    public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
    {         
        string connectionStringName = config["connectionStringName"];

        AzureProvidersHelper.UpdateConnectionString(connectionStringName, AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName), 
            AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName + "ProviderName"));

        base.Initialize(name, config);
    }
}

这是帮助类 AzureProvidersHelper.cs:

public static class AzureProvidersHelper
{
    internal static string GetRoleEnvironmentSetting(string settingName)
    {
        try
        {
            return RoleEnvironment.GetConfigurationSettingValue(settingName);
        }
        catch
        {
            throw new ConfigurationErrorsException(String.Format("Unable to find setting in ServiceConfiguration.cscfg: {0}", settingName));
        }
    }

    private static void SetConnectionStringsReadOnly(bool isReadOnly)
    {
        var fieldInfo = typeof (ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
        if (
            fieldInfo != null)
            fieldInfo.SetValue(ConfigurationManager.ConnectionStrings, isReadOnly);
    }

    private static readonly object ConnectionStringLock = new object();

    internal static void UpdateConnectionString(string name, string connectionString, string providerName)
    {
        SetConnectionStringsReadOnly(false);

        lock (ConnectionStringLock)
        {
            ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["name"];
            if (connectionStringSettings != null)
            {
                connectionStringSettings.ConnectionString = connectionString;
                connectionStringSettings.ProviderName = providerName;
            }
            else
            {
                ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(name, connectionString, providerName));
            }
        }

        SetConnectionStringsReadOnly(true);
    }
}

这里的关键是 RoleEnvironment.GetConfigurationSettingValue 从 Azure 服务配置而不是 web.config 读取。

对于未指定提供程序的实体框架,我必须使用帮助程序类中的 GetRoleEnvironmentSetting() 方法再次将此调用添加到 Global.asax:

var connString = AzureProvidersHelper.GetRoleEnvironmentSetting("ClientspaceDbContext");

        Database.DefaultConnectionFactory = new SqlConnectionFactory(connString);

这个解决方案的好处是您最终不必处理 Azure 角色 onstart 事件。

享受

冲刺

于 2013-05-22T13:16:28.883 回答
0

大卫,

一个不错的选择是使用 Azure 配置。如果右键单击 Azure 项目,可以添加额外的配置。将您的连接字符串放入正确的配置中(例如,ServiceConfiguration.WestCoast.cscfg、ServiceConfiguration.EastCoast.cscfg 等)。

在您的构建脚本中,使用配置名称将 TargetProfile 属性传递给 MSBuild,这些设置将构建到最终的 cscfg 中。

如果您遇到任何问题,请告诉我。我采用了这种方法,并且尝试了几次才能使其正常工作。一些可能有帮助的细节

埃里克

于 2013-04-16T18:57:42.400 回答