65.9K
CodeProject 正在变化。 阅读更多。
Home

自定义默认 AppSettings 和 ConnectionStrings 表达式生成器

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2009年3月25日

CPOL

4分钟阅读

viewsIcon

28212

downloadIcon

105

在不同环境(开发/测试/生产)中使用表达式生成器。

引言

我使用 CodeProject 已经很多年了,一直想尝试做出贡献。这是第一次尝试,我希望有人会觉得它有用,即使它不是最优雅的。

这个想法是使多个环境(开发/测试/生产等)的所有配置数据都可以在单个 web.config 文件中获得。

背景

过去我开发 Web 应用程序时,总是难以拥有适用于我的本地机器、共享开发机器和共享生产机器的不同设置集。它们都需要稍微不同的配置,特别是连接到不同数据库的连接字符串。我设法在 ASP.NET 1.1 中使用我自己的类来克服它,这些类可以确定要使用哪一组设置。

使用 ASP.NET 2.0,我再次遇到了这个限制,因为我无法再这样做,并且仍然必须使用表达式,例如,用于 SQLDataSourceObjectDataSource。最后,在我手头有一些时间并喜欢一篇关于使用表达式生成器的文章中的想法后,我开始制作一些可以为我完成这项工作的东西。请注意,我没有尝试查看这是否适用于 ASP.NET 3.0 或 3.5。

这个想法是替换默认的表达式生成器,这意味着我的新 DLL 将在几分钟内插入,并且除了 web.config 之外不需要任何更改。

使用代码

要使用 DLL,请添加对其的引用,然后在 web.config 中添加以下内容

<compilation debug="true">
  <expressionBuilders>
    <remove expressionPrefix="AppSettings"/>
    <remove expressionPrefix="ConnectionStrings"/>

    <add expressionPrefix="AppSettings" 
      type="Cottle.IT.ExpressionBuilders.MyAppSettingsExpressionBuilder, 
            Cottle.IT.ExpressionBuilders"/>
    <add expressionPrefix="ConnectionStrings" 
      type="Cottle.IT.ExpressionBuilders.MyConnectionStringsExpressionBuilder, 
            Cottle.IT.ExpressionBuilders"/>
  </expressionBuilders>
</compilation>

默认的表达式生成器被删除,并替换为我们的表达式生成器。

两个表达式生成器都需要一些帮助来确定它们在哪个环境中运行。为此,它们查看 SERVER_NAME 服务器变量,并将其与一组具有特定名称的 AppSettings 变量进行比较

<appSettings>
  <add key="ServerRegion{Prod}" value="localhost"/>
  <add key="ServerRegion{Dev}" value="localhostd"/>

然后,以类似的方式设置其他设置,无论是 appSettings 还是 connectionStrings

  <add key="{Prod}Setting1" value="Setting 1 on Prod"/>
  <add key="{Prod}Setting2" value="Setting 2 on Prod"/>
  <add key="{Dev}Setting1" value="Setting 1 on Dev"/>
  <add key="{Dev}Setting2" value="Setting 2 on Dev"/>
  <add key="abc" value="Can be any"/>
</appSettings>
<connectionStrings>
  <add name="{Dev}NorthwindConnectionString"
       connectionString="Data Source=DevServer;Initial Catalog=Northwind;
                         Integrated Security=True"
       providerName="System.Data.SqlClient" />
  <add name="{Prod}NorthwindConnectionString"
       connectionString="Data Source=ProdServer;Initial Catalog=Northwind;
                         Integrated Security=True"
       providerName="System.Data.SqlClient" />
</connectionStrings>

网站或 Web 应用程序中的所有其他内容都可以保持不变,并按预期使用。

实现

这两个类以类似的方式创建 - 它们包含稍微修改的标准 AppSettings 和 ConnectionStrings 表达式生成器中的代码。 我通过使用 Reflector 获取了代码。

首先,我创建了一个小型助手类,其中包含几个静态方法,这两个类都使用这些方法。第一个方法通过查看 SERVER_NAME 服务器变量来确定我们是否在开发/测试/生产等环境中,然后查找所有以“ServerRegion”开头的键的 AppSettings。然后,它返回匹配项的括号和其中的名称

internal static string ServerRegion()
{
  string whichServer = 
    HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
  string whichServerRegion = null;

  // Loop through all the AppSettings, looking for ServerRegion Keys
  // and then find a match against our server
  foreach (string key in ConfigurationManager.AppSettings.AllKeys)
  {
    if (key.StartsWith("ServerRegion", StringComparison.CurrentCultureIgnoreCase))
    {
      if (String.Compare(whichServer, ConfigurationManager.AppSettings[key], true) == 0)
      {
        Regex regex = new Regex("\\{(?<textinsidebrackets />\\w+)\\}");
        Match match = regex.Match(key);
        if (match.Success)
        {
          whichServerRegion = match.Groups["TextInsideBrackets"].Value;
          break;
        }
      }
    }
  }

  if (whichServerRegion == null)
    throw new InvalidOperationException("No Server Region Keys" + 
                                        " matching current server name");

  return "{" + whichServerRegion + "}";
}

另一种方法利用服务器区域,并将其与 appSetting 键组合以查找可以返回的设置。因此,它将查找设置为 Region + Key 或 Key + Region 以及最后 Key 的键。 最后一个是可用的,以便我们可以拥有一个所有环境通用的设置。

internal static string GetAppSetting(string key)
{
  string region = ServerRegion();
  string str;

  str = ConfigurationManager.AppSettings[region + key];
  if (str == null)
  {
    str = ConfigurationManager.AppSettings[key + region];
    if (str == null)
    {
      str = ConfigurationManager.AppSettings[key];
    }
  }
  return str;
}

在 AppSetting 表达式生成器中,我们然后更改 GetAppSetting 方法以返回我们的助手的 GetAppSetting。 我保留了所有剩余的方法不变,因为我在 Reflector 中找到了它们。

public static object GetAppSetting(string key)
{
  string str = Helper.GetAppSetting(key);
  if (str == null)
  {
    throw new InvalidOperationException("AppSetting_not_found");
  }
  return str;
}

ConnectionString 表达式生成器执行非常相似的操作。

关注点

这是获得我需要的东西的正确方法吗? 可能不是。 我早就知道,我找到以前从未做过的事情的机会非常小。 但是,我已经断断续续地搜索类似的东西很长时间了。 所以,就目前而言,这是我拥有的最好的。 我欢迎评论,但请不要太严厉地批评我。

我遇到的一个限制是使用在 web.config 中声明的任何 Membership / Role Providers。 它们似乎没有使用表达式生成器的连接字符串版本,而是更喜欢直接获取它。 我并没有大量使用这两者,而是更喜欢使用 Windows 身份验证和组员资格来确定访问权限。 但是,我一直在处理 Membership 和 Role Providers 的精简版本,我将调整它们以使用表达式构建的连接字符串。

历史

  • 2009 年 3 月 25 日:第一个版本。
© . All rights reserved.