在运行时更改web.config连接字符串的最佳方法是什么?

4
我对ASP.NET的世界还比较陌生,所以我在如何配置连接字符串并使整个应用程序使用该连接字符串方面遇到了一些困难。以下是关于我计划构建的应用程序的更多信息:
- 应用程序使用表单身份验证,而不是Windows身份验证。 - 将有一个登录页面,用户在该页面上提供其SQL Server登录ID和密码。 - 为了简化操作,我希望所有SQLDataSource控件都指向web.config连接字符串。这将在设计时完成,而不是通过编程设置。因此,它们将具有以下属性:ConnectionString="<%$ ConnectionStrings:MyDB %>"。 - 我想找到一种方法,在运行时更改"MyDB"连接字符串,使其使用用户提供的登录ID和密码。但是我不希望将其保存到web.config中。它应仅在该用户的会话期间有效。
人们通常如何处理这种情况?我认为一种方法是创建一个Session变量来存储连接字符串,然后在页面加载期间编程更改每个SQLDataSource控件的ConnectionString属性。但是如果可能的话,我希望避免这种方法。
由于许多人询问为什么我希望为每个用户使用唯一的连接,并担心缺乏池化,所以我认为我应该在这里发表评论,而不是在每个单独的响应中发表评论。
这个应用程序的性质要求每个用户都使用自己的帐户连接到数据库。后端安全性与他们的用户帐户相关,因此我们不能使用通用帐户,如"user"和"administrator"。我们还需要知道每个用户的具体身份以进行审计控制。该应用程序通常只有10至20个用户,因此缺乏池化并不是一个问题。我们可以另外讨论这种方法的优点,但不幸的是,我在这里没有选择 - 该项目要求每个用户都使用自己的帐户连接到数据库。
我很想要求Windows身份验证,但不幸的是,该应用程序的某些实现将需要SQL身份验证。
如果我只能像这样声明SQLDataSource控件时设置连接字符串,那就太棒了:
  <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString = "<%= Session("MyConnectionString") %>"
    SelectCommand="SELECT * FROM [Customers]">
  </asp:SqlDataSource>

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

非常感谢大家的帮助!

9个回答

6

如果您不想深入了解代码背后的内容,还有另一种方法可以实现此目的。

首先阅读这篇关于表达式生成器的文章。这是我喜欢在Web应用中使用的东西之一!

现在来看一些代码:

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

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中注册表达式生成器,如下所示。
...
<compilation debug="false">
  <expressionBuilders>
    <add expressionPrefix="Code" type="MyNamespace.Web.Compilation.CodeExpressionBuilder"/>
  </expressionBuilders>
</compilation>
...

(上述所有代码都来自这里,稍作修改)

最后将您的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的新手,所以我花了一个下午来尝试这个表达式生成器方法,它正是我需要的。我已经在Classic ASP中编码了好几年了,而在ASP.NET中你可以做到令人难以置信的事情! - CowherPower

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

所以这种方法要求我在页面加载期间通过编程方式设置所有SQLDataSource控件的连接字符串,对吗?我希望避免这样做。 - CowherPower
你可以从SqlDataSource继承一个类,并在加载时将其连接字符串设置为Session变量。然后,您可以使用tagMapping将SqlDataSource标记重新映射到自己的控件。 - Mehrdad Afshari
非常感谢您的帮助!我尝试使用TagMapping并创建自己的SQLDataSource类,它起作用了!但最终我发现在我的情况下,自定义表达式生成器方法效果更好。 - CowherPower

1

我认为你有几个选择,一些可以利用现有的资源,而另一些则需要你进行更改。

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

  2. 实现Windows身份验证和身份模拟,并设置具有访问SQL Server框的Windows帐户。

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

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


1
我不建议你这样做,因为你将会面临可扩展性问题。Web应用程序将无法使用连接池,并且将打开与访问它的用户数量相同的连接。你也将有很多真实的连接打开和关闭。
如果你决定继续:
  • 如果你可以使用Windows身份验证,请使用模拟+集成模式进行SQL连接。使用Windows组在SQL服务器上设置权限。
  • 你可以递归访问页面上的所有项,查找sqldatasources,并将连接应用于每个项。你可以从global.asax附加到页面的oninit,这样你就可以将其应用于所有页面。
为什么你想以这种方式做呢?涉及到哪些限制?(通常在Web应用程序中使用受信任的子系统模型,即在Web应用程序级别或单独的业务层级别进行身份验证/授权)

请查看我添加的一般注释,了解我需要以这种方式进行的原因。但是,如果在声明控件时不能设置连接字符串,则使用OnInit的建议听起来很有趣。您知道在哪里可以找到一个易于理解的示例吗? - CowherPower

0
一个我正在使用的方法(我忘记在哪里学到的)是在应用程序启动时添加一个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";
}

0

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

SqlDataSource1.ConnectionString = ConnectionString;

如果您想确保不使用默认值,可以将默认值设置为无效的连接字符串并处理异常,或者仅在其为默认值时检查并抛出错误。您还可以在数据源选择事件期间检查用户是否已登录,并在未登录时取消该事件...


0

如果不将其保存到web.config中,则无法完成此操作。


0
如Mitch所说,如果用户使用不同的凭据登录(如果这导致不同的连接字符串),则会失去连接池。
如果您只是担心将管理员用户与普通用户分开,请使用2个连接字符串,一个用于管理员,另一个用于普通用户。使用 asp.net角色提供程序为用户提供适当的权限。

0
你可以使用像Postsharp这样的面向方面编程库,在运行时动态地更改连接字符串。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接