【问题标题】:What is the best method for changing a web.config connectionstring at runtime?在运行时更改 web.config 连接字符串的最佳方法是什么?
【发布时间】:2010-10-12 06:55:24
【问题描述】:

我对 ASP.NET 世界还很陌生,因此在想出在运行时配置连接字符串并让整个应用程序使用该连接字符串的最佳方法时遇到了一些麻烦。以下是有关我计划构建的应用程序的更多信息:

  • 应用程序使用表单身份验证,而不是 Windows 身份验证
  • 会有一个登录页面,用户在其中提供他们的 SQL Server 登录 ID 和密码
  • 为简单起见,我希望所有 SQLDataSource 控件都指向一个 web.config 连接字符串。这将在设计时完成,而不是以编程方式设置它们。所以,他们会有这样的属性: ConnectionString=""
  • 我想找到一种在运行时更改“MyDB”连接字符串的方法,以便它使用用户提供的登录 ID 和密码。但我不希望将其保存到 web.config。它应该只对该用户的会话有效。

人们通常这样做的“标准”方式是什么?我假设一种方法是使用连接字符串创建一个 Session 变量,然后在页面加载期间以编程方式更改每个 SQLDataSource 控件的 ConnectionString 属性。但我希望尽可能避免这种情况。


由于许多人问我为什么要为每个用户使用唯一的连接并且担心缺乏池,我想我会在这里对此发表评论,而不是对每个单独的回复发表评论。

此应用程序的性质要求每个用户都使用自己的帐户连接到数据库。后端安全性与他们的用户帐户相关联,因此我们不能使用“用户”和“管理员”等通用帐户。我们还需要知道每个用户的具体身份来进行审计控制。该应用程序通常只有 10 到 20 个用户,因此无需担心缺少池。我们可以再讨论一下这种方法的优点,但不幸的是我在这里没有选择 - 该项目要求每个用户使用自己的帐户连接到数据库。

我很想要求 Windows 身份验证,但不幸的是,此应用程序的某些实现需要 SQL 身份验证。

如果我可以像这样声明 SQLDataSource 控件时设置连接字符串,那就太简单了:

  <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString = "<%= Session("MyConnectionString") %>"
    SelectCommand="SELECT * FROM [Customers]">
  </asp:SqlDataSource>

但我收到一个错误,因为它不喜欢那里的 标记。如果我在声明控件时无法执行此操作,那么以编程方式为应用程序中的每个 SQLDataSource 控件执行此操作的最简单方法是什么?

非常感谢大家的帮助!

【问题讨论】:

    标签: asp.net database authentication web-applications


    【解决方案1】:

    如果您不想深入研究背后的代码,还有另一种方法可以做到这一点。

    首先阅读这篇文章expression builders。我最喜欢带入我的网络应用程序的东西之一!

    现在是一些代码:

    首先在您的项目中创建一个包含以下内容的类:

    using System;
    using System.CodeDom;
    using System.Web.UI;
    using System.Web.Compilation;
    
    namespace MyNamespace.Web.Compilation
    {
        [ExpressionPrefix("code")]
        public class CodeExpressionBuilder : ExpressionBuilder
        {
            public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
               object parsedData, ExpressionBuilderContext context)
            {
                return new CodeSnippetExpression(entry.Expression);
            }
        }
    
    }
    

    然后,在 web.config 中注册 Expression Builder,如下所示

    ...
    <compilation debug="false">
      <expressionBuilders>
        <add expressionPrefix="Code" type="MyNamespace.Web.Compilation.CodeExpressionBuilder"/>
      </expressionBuilders>
    </compilation>
    ...
    

    (以上所有代码均取自here并稍作修改)

    最后将您的 SqlDataSource 更改为以下 (C#):

    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
        ConnectionString='<%$ code: (string)Session["MyConnectionString"] ?? ConfigurationManageer.ConnectionStrings["myDefaultConn"].ConnectionString %>'
        SelectCommand="SELECT * FROM [Customers]">
    </asp:SqlDataSource>
    

    如果你想(我会推荐)创建一个静态类来为你处理连接字符串,可以这样说:

    public static ConnectionManager
    {
       public static string GetConnectionString()
       {
          return HttpContext.Current.Session["MyConnectionString"] as string ??
                 ConfigurationManager.ConnectionStrings["DefaultConnectionStr"].ConnectionString;
       }
    }
    

    那么你的 SqlDataSource 将是

    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
        ConnectionString='<%$ code: ConnectionManager.GetConnectionString() %>'
        SelectCommand="SELECT * FROM [Customers]">
    </asp:SqlDataSource>
    

    这样,如果您需要更改获取连接字符串的方式,您可以在一处完成!

    【讨论】:

    • 优秀!!太感谢了!我是 ASP.NET 的新手,所以我花了一个下午的时间来研究这个表达式生成器方法,这正是我所需要的。多年来,我一直在经典 ASP 地狱中编写代码,您在 ASP.NET 中可以做到的事情令人难以置信!
    【解决方案2】:

    将Web.config 连接字符串加载到Session_Start 中的会话变量。如果用户提供了他/她自己的凭据,请在会话变量中更新它们。否则,默认值(web.config 值)将生效。

    【讨论】:

    • 所以这种方法需要我在页面加载期间以编程方式设置所有 SQLDataSource 控件上的连接字符串,对吗?我希望避免这样做。
    • 您可以从 SqlDataSource 继承一个类,并在加载时从 Session 变量设置它的连接字符串。然后,您可以使用tagMapping 将 SqlDataSource 标记重新映射到您自己的控件。
    • 非常感谢您的帮助!我尝试使用 TagMapping 并创建自己的 SQLDataSource 类,它成功了!但最后我发现自定义表达式构建器方法在我的情况下效果更好。
    【解决方案3】:

    我会说你有几个选择,有些可以使用你所拥有的,有些则需要你改变一些东西。

    1. 将默认连接存储在 web.config 中,将其加载到会话中,使用它直到用户登录,然后稍后更新会话中的值。

    2. 实施 windows 身份验证和身份模拟,并设置 windows 帐户以访问 SQL Server 框。

    如果您使用第一个项目,请创建一个共享帮助函数来获取连接,首先检查会话,然后从 web.config 加载。这样,您的所有数据源仍然可以在设计时绑定。

    注意:这不是典型情况,使用多个 SQL Server 帐户进行连接会影响性能,例如无法在其他项目中使用连接池。

    【讨论】:

      【解决方案4】:

      我不建议您这样做,因为您会遇到可伸缩性问题。 Web 应用程序将无法使用连接池,并且将打开与访问它的用户一样多的连接。您还将有许多真正的连接打开/关闭。

      如果您决定继续:

      • 如果可以使用windows认证,则sql连接使用impersonation+integrated方式。使用 windows 组在 sql server 上设置权限。
      • 您可以递归地访问页面上的所有项目,查找 sqldatasources,并将连接应用到每个项目。您可以从 global.asax 附加到页面的 oninit,以便将其应用于所有页面。

      为什么要这样做?涉及的约束是什么? (通常在 Web 应用程序上使用受信任的子系统模型,即在 Web 应用程序级别/或在单独的业务层完成身份验证/授权)

      【讨论】:

      • 请参阅我添加的一般性评论,了解我为什么需要这样做。但是,如果在声明控件时我无法设置连接字符串,那么您对使用 OnInit 的建议听起来很有趣。你知道我在哪里可以找到一个简单的例子吗?
      【解决方案5】:

      如果不将其保存到 web.config,则无法执行此操作。

      【讨论】:

        【解决方案6】:

        正如 Mitch 所说,如果您让用户使用不同的凭据登录(如果这会导致不同的连接字符串),则会丢失连接池。

        如果您只是担心将管理员用户与普通用户分开,只需设置 2 个连接字符串,一个用于管理员,一个用于普通用户。使用asp.net role providers 为用户提供适当的权限。

        【讨论】:

          【解决方案7】:

          您可以使用 Postsharp 等方面编程库,在运行时动态更改连接字符串。

          【讨论】:

            【解决方案8】:

            我正在使用的一种方法(我忘记了我从哪里了解到的)是在应用程序启动时添加一个SettingsLoaded 处理程序,然后在处理程序中设置新的连接字符串。我没有在 ASP.NET 中尝试过这个,只是一个本地应用程序,所以你的里程可能会有所不同:

            Settings.Default.SettingsLoaded += new System.Configuration.SettingsLoadedEventHandler(Default_SettingsLoaded);
            
            void Default_SettingsLoaded(object sender, System.Configuration.SettingsLoadedEventArgs e)
            {
                Settings.Default["ConnectionString"] = "my new connection string";
            }
            

            【讨论】:

              【解决方案9】:

              我也有类似的情况。我将连接字符串设置为 web.config 中的默认连接字符串。然后在后面的代码中,您可以将连接字符串设置为不同的值。您必须在 Page_Load 中执行此操作,在数据源选择事件触发之前,像这样......

              SqlDataSource1.ConnectionString = ConnectionString;
              

              如果要确保不使用默认值,可以将默认值设为非工作连接字符串并处理异常,或者仅检查它是否为默认值,如果是则抛出错误。您也可以在数据源的选择事件期间检查用户是否已登录,如果没有则取消该事件...

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2014-03-19
                • 2010-09-28
                • 2014-01-25
                • 2022-11-04
                • 2010-09-24
                • 2016-12-11
                • 2017-11-17
                • 1970-01-01
                相关资源
                最近更新 更多