在ASP.NET中编写自己的提供程序类

| 注意:我不想编写自定义成员资格提供程序。 我想编写自己的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 \”。我正计划使其充满活力。 所以我想知道是否可以使其像静态的内置Membership类一样,在其中可以在web.config中定义connectionStringName。这样,可以使类可重用,而不必始终将web.config中的连接字符串命名为\“ MyConnString \”。 1:我不想在每个静态方法中将连接字符串作为参数传递。 2:我必须能够访问类似于Membership.CreateUser的方法,即静态方法。 我正在并行浏览网络,但是任何输入/指导都会有所帮助。 编辑:我已经更新了代码示例,以消除一些有关使用静态类的问题的困惑。这是我发布的一个新问题,以澄清这一点。抱歉造成混乱。     
已邀请:
        我能想到的唯一符合您提出的条件的方法是使用依赖项注入,静态构造函数,并注入类似“ 2”的内容。这似乎是我能想到的最复杂的事情,所以您可能会喜欢。 :) 编辑 阅读评论后,您似乎只想能够引用任何连接字符串,但每个应用程序只能引用一个连接字符串。我想说的只是在
appSettings
中添加一个名为
MySqlProviderConnection
的元素,其值就是您要使用的连接字符串的名称。 然后在您的助手中,检查appsetting是否存在,获取其值,并将其传递给您的
ConfigurationManager.ConnectionStrings
调用。这样,您的提供商就可以使用所需的任何连接,而无需更改任何代码。     
我通常不鼓励跨多个请求共享一个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
属性,并且可以扩展为包含错误。 只要使用此“ 9”中的任何一个,就可以了,只要您启用一种方法来创建provider类的单例实例,并且继续不共享任何可变属性(可能在各种请求/线程之间)。您可能需要考虑某种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
}
在处理结果时没有关闭连接。如果您在示例中注意到,则我们的
SqlClient
对象具有
using
语句。这种方法允许将结果集处理与“ 13”解耦,因为提供者类将处理可能重复的SQL提供代码,将结果处理委托给调用者,然后继续其操作(即关闭连接) 。 至于IoC / DI,我个人使用温莎城堡。您可以将依赖对象作为属性或构造参数注入。将控制反转容器注册为依赖项资源管理器将使您(除其他事项外)在请求一种资源时返回相同的对象。基本上,对于每个需要使用
MySqlHelper
的调用方类,可以在实例化调用方类或调用方类引用其公共
MySqlHelper
属性时注入相同的实例。我个人更喜欢尽可能的构造函数注入。另外,当我说注入时,我的意思是您不必担心设置属性值,因为IoC / DI会为您设置属性值(如果配置正确)。请参阅此处以获得更深入的说明。 另外要注意的是,只有当您的类是非静态的时,IoC / DI方法才真正起作用,以便每个应用程序可以拥有自己的单例实例。如果
MySqlHelper
是静态的,那么除非传递它,否则您只能支持一个连接字符串,而在您最初的问题中,您不希望这样做。 IoC / DI将允许您使用“ 13”属性成员,就好像它是静态的一样,尽管已注册的容器将确保该属性具有适当的实例。     
        这是我在一些小型项目上使用的ѭ18的完整代码。 但是对于这类课程,要
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
即可。     

要回复问题请先登录注册