Написание своего собственного класса провайдера в ASP.NET - PullRequest
0 голосов
/ 27 мая 2011

Примечание: я не хочу писать собственный провайдер членства.

Я хочу написать свой собственный класс провайдера, чтобы я мог определить его в web.config и получить к нему доступ как класс членства.

Вот пример моего класса (у него много других статических методов):

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, где я могу определить connectionStringName в web.config.Таким образом, класс можно использовать повторно, не называя мою строку подключения в web.config как «MyConnString».

1: Я НЕ хочу передавать строку подключения в каждом статическом методе в качестве параметра.

2: У меня должна быть возможность доступа к методам, похожим на Membership.CreateUser, то есть static.

Я параллельно просматриваю Интернет, но любые входные данные / указания помогут. Отредактировано: Я обновил мой пример кода, чтобы устранить путаницу в вопросах, связанных со статическим классом.Вот новый вопрос Я отправил, чтобы уточнить это.Извините за путаницу.

Ответы [ 3 ]

2 голосов
/ 27 мая 2011

единственное, что я могу придумать, что соответствует требованиям, которые вы изложили, - это использовать инъекцию зависимостей, статический конструктор и внедрять что-то вроде IConnectionStringProvider.Кажется, это самая запутанная вещь, о которой я могу подумать, так что она вам может понравиться.:)

edit

после прочтения вашего комментария кажется, что вы просто хотите иметь возможность ссылаться на любую строку подключения, но только одну строку подключения на приложение.я бы сказал, просто добавьте элемент к appSettings с именем MySqlProviderConnection, значение которого будет именем строки подключения, которую вы хотите использовать.

, затем в вашем помощнике проверьте наличие набора параметров,получите его значение и передайте его вашему вызову ConfigurationManager.ConnectionStrings.таким образом, ваш провайдер может использовать любое соединение, которое вы хотите, без изменения какого-либо кода.

1 голос
/ 27 мая 2011

Обычно я не рекомендую использовать один экземпляр SqlConnection для нескольких запросов.Даже если вы включите MARS , у вас могут возникнуть проблемы с производительностью.Я думаю, что когда ваше соединение получает команду не для чтения, буфер соединения приостановит все текущие чтения, пока запись не закончится.Единственное, что вы действительно экономите, это время, которое требуется для установления соединения.

SqlConnections pooled , поэтому вы можете настроить провайдера так, чтобы минимальное / максимальное количество экземпляров было доступно длявымогательство клиентов.Имейте в виду, что это также контролируется любой базой данных, к которой вы подключаетесь;при условии, что вы подключаетесь к экземпляру 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 или Dependency Injection для предоставления строки подключения по вашему запросу.

EDIT

Выход позволяет вызывающей стороне использовать возвращенный объектперед тем, как контекст выполнения возвращается к методу, дающему возврат для продолжения выполнения.Таким образом, в приведенном выше примере вызывающая сторона может сделать что-то вроде этого:

// 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 .Вы можете внедрить объекты зависимостей как свойства или параметры построения.Регистрация контейнера Inversion of Control в качестве менеджера ресурсов зависимостей позволит вам (помимо прочего) возвращать тот же объект при запросе типа ресурса.По сути, для каждого класса вызывающего, который должен использовать MySqlHelper, вы можете внедрить один и тот же экземпляр, когда создается экземпляр класса вызывающего или когда класс вызывающего ссылается на свое открытое свойство MySqlHelper.Я лично предпочитаю инжекцию конструктора всякий раз, когда это возможно.Кроме того, когда я говорю «впрыскивать», я имею в виду, что вам не нужно беспокоиться об установке значения свойства, поскольку ваш IoC / DI делает это за вас (если он настроен правильно).См. здесь для более подробного объяснения.

В качестве еще одного примечания, подход IoC / DI действительно вступил бы в игру, только если ваш класс нестатичен, так что каждое приложение может иметь своесобственный экземпляр синглтона.Если MySqlHelper является статическим, то вы можете поддерживать только одну строку подключения, если вы не передадите ее, что в исходном вопросе вы бы предпочли не делать.IoC / DI позволит вам использовать ваш элемент свойства MySqlHelper, как если бы он был статическим, поскольку зарегистрированный контейнер будет гарантировать, что свойство имеет правильный экземпляр.

0 голосов
/ 27 мая 2011

Вот полный код SqlHelper, который я использовал в некоторых небольших проектах.Но осторожно с static для такого рода занятий.Если вы будете использовать его для веб-проекта, помните, что подключение будет совместно использоваться одним и тем же экземпляром для всех пользователей, что может вызвать проблемы ...

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 для всех методов.

...