0

注意:我不想编写自定义会员提供程序。

我想编写自己的 Provider 类,以便可以在 web.config 中定义它并像 Membership 类一样访问它。

这是我的类的一个示例(它有许多其他静态方法):

public static class MySqlHelper
{
    private static string constring = ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString;

    public static int ExecuteNonQuery(string mysqlquery)
    {
        SqlConnection conn = new SqlConnection(connString);
    SqlCommand cmd = new SqlCommand(mysqlquery, conn);
    int result;

    try
    {
        conn.Open();
        result= cmd.ExecuteNonQuery();
    }
    finally
    {
        conn.Close();
    }
    return result;

    }
}

用法:MySqlHelper.ExecuteNonQuery("select * from customers");

现在如您所见,我已经硬编码了连接字符串的名称,即“MyConnString”。我打算让它动态化。

所以我想知道我是否可以让它像静态内置成员资格类一样,我可以在 web.config 中定义 connectionStringName。这样,可以使该类可重用,而不必总是将 web.config 中的连接字符串命名为“MyConnString”。

1:我不想在每个静态方法中将连接字符串作为参数传递。

2:我必须能够访问类似于 Membership.CreateUser 的方法,即静态的。

我正在并行查看网络,但任何输入/指导都会有所帮助。

编辑:我已经更新了我的代码示例,以消除对使用静态类问题的一些混淆。这是我发布的一个新问题以澄清这一点。很抱歉混淆了。

4

3 回答 3

2

我能想到的唯一符合您提出的条件的方法是使用依赖注入、静态构造函数,并注入类似IConnectionStringProvider. 这似乎是我能想到的最令人费解的事情,所以你可能会喜欢它。:)

编辑

阅读您的评论后,您似乎只想能够引用任何连接字符串,但每个应用程序只能引用一个连接字符串。我想说只是添加一个元素来appSettings命名MySqlProviderConnection,其值是您要使用的连接字符串的名称。

然后在你的助手中,检查 appsetting 是否存在,获取它的值,并将其传递给你的ConfigurationManager.ConnectionStrings调用。这样您的提供商就可以使用您想要的任何连接,而无需更改任何代码。

于 2011-05-27T17:35:59.217 回答
1

我通常不鼓励在多个请求中共享一个 SqlConnection 实例。即使启用MARS,也可能会遇到性能问题。我认为当您的连接收到非读取命令时,连接缓冲区将暂停所有当前读取,直到写入完成。您真正节省的唯一一件事是建立连接所需的时间。

SqlConnections 是化的,因此您可以将提供程序配置为具有可用于请求客户端的最小/最大实例数。请记住,这也由您连接到的任何数据库控制;假设您要连接到 SQL Server 实例,SQL Server 有自己的最大允许连接数设置。

我建议让您的公共成员接受命令字符串或命令参数,而不是允许客户端确定何时打开/关闭共享的 SqlConnection 实例。然后,类似于您的示例所建议的,从池中打开一个连接并执行该命令。

public IEnumerable<SqlResults> ExecuteStoredProcedure(string procedure, params SqlParameter[] parameters) {
    using(SqlConnection connection = new SqlConnection(MyConnectionStringProperty)) {
        try {
            connection.Open();

            using(SqlCommand command = new SqlCommand(procedure, connection)) {
                command.CommandType = CommandType.StoredProcedure;

                if(parameters != null) {
                    command.Parameters.AddRange(parameters);
                }

                // yield return to handle whatever results from proc execution
                // can also consider expanding to support reader.NextResult()
                using(SqlDataReader reader = command.ExecuteReader()) {
                    yield return new SqlResults {
                        Reader = reader;
                    };
                }
            }
        }
        finally {
            if(connection.State != ConnectionState.Closed) {
                connection.Close();
            }
        }
    }
}

上面的示例代码就是这样——我在工作中使用的一个概念示例。该示例现在确实具有最大化的错误处理,但在返回和处理结果的方式上非常灵活。该类SqlResults仅包含一个SqlDataReader属性,并且可以扩展为包含错误。

只要static您启用一种方法来制作提供者类的单例实例并且继续不共享任何可变属性(可能跨各种请求/线程),就可以进行任何操作。您可能需要考虑某种 IoC 或依赖注入方法来根据您的请求提供连接字符串。

编辑

Yield 允许调用者在执行上下文返回到产生返回以继续执行的方法之前使用返回的对象。因此,在上面的示例中,调用者可以执行以下操作:

// Since it's an IEnumerable we can handle multiple result sets
foreach(SqlResults results in MySqlHelper.ExecuteStoredProcedure(myProcedureName, new SqlParameter("myParamName", myParamValue)) {
    // handle results
}

在我们处理结果时没有关闭连接。如果您在示例中注意到,我们有using我们的SqlClient对象的声明。这种方法允许将结果集处理与结果集处理分离,MySqlHelper因为提供者类将处理可能重复的 SQL 提供代码,将结果处理委托给调用者,然后继续它必须做的事情(即关闭连接)。

至于 IoC/DI,我个人使用Castle Windsor。您可以将依赖对象作为属性或构造参数注入。将控制反转容器注册为依赖资源管理器将允许您(除其他外)在请求某种资源时返回相同的对象。基本上,对于每个需要使用的调用者类MySqlHelper,您可以在调用者类被实例化或调用者类引用其公共MySqlHelper属性时注入相同的实例。我个人更喜欢构造函数注入。另外,当我说注入时,我的意思是您不必担心设置属性值,因为您的 IoC/DI 会为您执行此操作(如果配置正确)。有关更深入的解释,请参见此处。

另外需要注意的是,IoC/DI 方法只有在您的类是非静态的时才会真正发挥作用,这样每个应用程序都可以拥有自己的单例实例。如果MySqlHelper是静态的,那么除非您将其传入,否则您只能支持一个连接字符串,在您最初的问题中,您不希望这样做。IoC/DI 将允许您使用您的MySqlHelper属性成员,就好像它是静态的一样,因为注册的容器将确保该属性具有正确的实例。

于 2011-05-27T18:46:34.607 回答
0

这是SqlHelper我在一些小项目中使用的完整代码。static但是对于这种类要小心。如果您将它用于 Web 项目,请记住连接将在同一实例中为所有用户共享,这可能会导致严重问题...

using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;

public class SqlHelper
{
    private SqlConnection connection;

    public SqlHelper()
    {
        connection = new SqlConnection();
    }

    public void OpenConnection()
    {
        // Updated code getting the ConnectionString without hard naming it.
        // Yes, if you have more than 1 you'll have problems... But, how many times it happens?

        if (WebConfigurationManager.ConnectionStrings.Length == 0)
            throw new ArgumentNullException("You need to configure the ConnectionString on your Web.config.");
        else
        {
            connection.ConnectionString = WebConfigurationManager.ConnectionStrings[0].ConnectionString;
            connection.Open();
        }
    }

    public void CloseConnection()
    {
        if (connection != null && connection.State != ConnectionState.Closed)
            connection.Close();
    }

    public DataTable ExecuteToDataTable(string sql)
    {
        DataTable data;

        SqlCommand command = null;
        SqlDataAdapter adapter = null;

        try
        {
            if (connection.State != ConnectionState.Open)
                OpenConnection();

            command = new SqlCommand(sql, connection);
            adapter = new SqlDataAdapter(command);

            retorno = new DataTable();
            adapter.Fill(data);
        }
        finally
        {
            if (command != null)
                command.Dispose();

            if (adapter != null)
                adapter.Dispose();

            CloseConnection();
        }

        return data;
    }

    public int ExecuteNonQuery(string sql)
    {
        SqlCommand command = null;

        try
        {
            if (connection.State != ConnectionState.Open)
                OpenConnection();

            command = new SqlCommand(sql, connection);
            return command.ExecuteNonQuery();
        }
        finally
        {
            if (command != null)
                command.Dispose();

            CloseConnection();
        }
    }

    public object ExecuteScalar(string sql)
    {
        SqlCommand command = null;

        try
        {
            if (connection.State != ConnectionState.Open)
                OpenConnection();

            command = new SqlCommand(sql, connection);
            return command.ExecuteScalar();
        }
        finally
        {
            if (command != null)
                command.Dispose();

            CloseConnection();
        }
    }
}

示例用法:

SqlHelper sql = new SqlHelper();
DataTable data = sql.ExecuteToDataTable("SELECT * FROM Customers");
int affected = sql.ExecuteNonQuery("INSERT Customers VALUES ('Test')");

但是,如果您真的想要static(如果您在单个用户环境中),只需static使用所有方法。

于 2011-05-27T17:27:07.643 回答