2013-12-18 4 views
4

В рамках моих общих утилит, которые я использовал в моей бизнес-приложений, у меня есть этот код ...Использование SqlDataSource из ситуаций неуправляющая

using System.Web.UI.WebControls; 

public class Database 
    { 
    /// <summary> 
    /// Creates a DataView object using the provided query and an SqlDataSource object. 
    /// </summary> 
    /// <param name="query">The select command to perform.</param> 
    /// <returns>A DataView with data results from executing the query.</returns> 
    public static DataView GetDataView(string query) 
     { 
     SqlDataSource ds = GetDBConnection(); 
     ds.SelectCommand = query; 
     DataView dv = (DataView)ds.Select(DataSourceSelectArguments.Empty); 
     return dv; 
     } 

    /// <summary> 
    /// Creates a SqlDataSource object with initialized connection string and provider 
    /// </summary> 
    /// <returns>An SqlDataSource that has been initialized.</returns> 
    public static SqlDataSource GetDBConnection() 
     { 
     SqlDataSource db = new SqlDataSource(); 
     db.ConnectionString = GetDefaultConnectionString(); //retrieves connection string from .config file 
     db.ProviderName = GetDefaultProviderName(); //retrieves provider name from .config file 
     return db; 
     } 
    } 

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

DataView dv=Database.GetDataView("select mycolumn from my table"); 
//loop through data and make use of it 

Я взял некоторое количество тепла от людей, для использования SqlDataSource таким образом. Людям, похоже, не нравится, что я использую веб-контроль исключительно из кода вместо того, чтобы помещать его на страницу ASPX. Это не похоже на них, но они не смогли сказать мне недостаток. Итак, есть ли недостаток? Это мой главный вопрос. Потому что, если есть много недостатков, мне, возможно, придется изменить, как я делаю много внутренних приложений, которые я разработал.

Мой класс базы данных работает даже в ситуациях, отличных от nonASP.NET, до тех пор, пока я добавляю сборку System.Web. Я знаю, что это небольшое увеличение размера пакета, но я чувствую, что это того стоит для типа приложения, которое я пишу. Есть ли недостаток в использовании SqlDataSource из программы WPF/Windows Forms/Console?

+1

Является ли этот код упрощенной версией вашего реального кода или вы никогда не передаете параметры по вашему запросу? Поскольку код, который вы опубликовали, приглашает [SQL Injection] (http://www.troyhunt.com/2013/07/everything-you-wanted-to-know-about-sql.html), если вам нужно пройти параметры. –

+0

@RichardDeeming Упрощенный, у меня есть другой код, который скрабы для SQL Injection. Полагаю, я должен упомянуть, что этот код используется для внутренних бизнес-приложений внутри нашей компании на 60 человек. Это не общедоступно. – mason

+0

И нет возможности внутренних пользователей, пытающихся взломать базы данных или вредоносные программы, попадающие в вашу сеть, не так ли? http://www.troyhunt.com/2013/10/your-corporate-network-is-already.html –

ответ

1

Ну, нет жестких правил, запрещающих кому-либо выполнять такую ​​реализацию.

Однако следующие вопросы, на которые необходимо ответить, перед выполнением этой реализации.

  1. Является ли это использование безопасным? (потому что есть все возможности, один и тот же вызов может быть выполнен несколькими приложениями-потребителями.
  2. Будет ли проведено многоуровневое дифференцирование (UI.Control используется в слое данных)?
  3. Что делать, если этот элемент управления устарел или ограничен в следующие рамочные релизы?
+0

Здесь нет проблем с потоками, потому что вызовы статические –

-1

единственные вопросы, которые я вижу в

(1) это, как изобретать колесо. Существует Enterprise библиотека v5 для FW3.5 и v6 для FW4.5, который содержит данные доступа. Используйте это.

С помощью EL вы можете позвонить и иметь 2,3,4 таблицы, загруженные в Dataset. С вашим методом это невозможно, только один в то время.

Корпоративная библиотека - это полный комплект доступа к данным, предоставляемый Microsoft. Он заботится обо всех мелочах, и все, что вам нужно, - это позвонить своим данным. Это полный уровень доступа к данным. И если вы посмотрите глубже, EL позволяет интегрировать Data и Caching и другие вещи. Но вам не нужно использовать то, что вам не нужно. Если вам нужен доступ к данным, вы можете использовать только это.

И (2) Как правило, это не хорошая идея написать сборку низкого уровня с высокоуровневой сборкой в ​​ссылке. Anything System.Web.... - это интерфейс и клиентский материал. В многоуровневом дизайне торта это похоже на верхнюю часть, а Data Access - внизу. Все ссылки [save for "common"] должны перемещаться снизу вверх, и вы имеете это в противоположном направлении.

Посмотрите на эту картину:

enter image description here

Это от Microsoft. Вы видите слои «торта». Все ссылки идут вверх. Что вы сделали - вы взяли компонент, связанный с пользовательским интерфейсом, и написали Data Access.

Вы можете называть это мнением - но это мнение является стандартной практикой и шаблоном в разработке программного обеспечения. Ваш вопрос также основан на мнениях. Потому что вы можете закодировать все в одном файле, один класс, и он будет работать. Вы можете установить ссылки на System.Windows.Forms в приложении Asp.net, если хотите. Технически, это возможно, но это действительно плохая практика.

Ваше приложение теперь имеет ограниченное повторное использование. Что делать, если вы пишете WPF-компонент или службу, которые должны использовать тот же доступ к данным. Вам нужно перетащить все System.Web?

+0

. Какое преимущество имеет у библиотеки предприятий то, что я уже делаю? Ваш второй пункт не несет никакого веса. Вы говорите: «Но это не значит, что нужно использовать этот путь!» не говоря _why_ это плохая идея. Если вы можете указать конкретные примеры того, почему это было бы плохой идеей, я был бы признателен. – mason

+0

@ msm8bball - см. Мои правки. Зачем? Потому что у вас нет разделения проблем. Читайте о «ТВЕРДОЙ». Вы создали микс UI-DataAccess. Это технически возможно (в этом случае, поскольку Microsoft предоставила компоненты для «быстрых исправлений»), но в хорошем дизайне приложений этого не произойдет. –

+0

Что касается вашего редактирования, я не вижу, как эта картина имеет значение. Вы не объясняете _why_ это плохая идея. Вы говорите, что это не _meant_, чтобы использоваться таким образом, не объясняя _why_, это плохая практика. Хотя SqlDataSource находится в пространстве имен, связанных с UI, вряд ли это связано с пользовательским интерфейсом. На самом деле, единственная причина, по которой я могу видеть, что они беспокоились о том, чтобы сделать ее элементом управления в первую очередь, - это то, что Microsoft может сказать: «ASP.NET может отображать данные без написания одной строки кода!» – mason

1

Учитывая, насколько легко заменить этот код, удалив искушение использовать динамические SQL-запросы для передачи параметров, я думаю, что вопрос должен быть: есть ли какая-либо польза для сохранения кода как есть?

Например:

public static class Database 
{ 
    private static readonly Func<DbCommandBuilder, int, string> getParameterName = CreateDelegate("GetParameterName"); 
    private static readonly Func<DbCommandBuilder, int, string> getParameterPlaceholder = CreateDelegate("GetParameterPlaceholder"); 

    private static Func<DbCommandBuilder, int, string> CreateDelegate(string methodName) 
    { 
     MethodInfo method = typeof(DbCommandBuilder).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null); 
     return (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), method); 
    } 

    private static string GetDefaultProviderName() 
    { 
     ... 
    } 

    private static string GetDefaultConnectionString() 
    { 
     ... 
    } 

    public static DbProviderFactory GetProviderFactory() 
    { 
     string providerName = GetDefaultProviderName(); 
     return DbProviderFactories.GetFactory(providerName); 
    } 

    private static DbConnection GetDBConnection(DbProviderFactory factory) 
    { 
     DbConnection connection = factory.CreateConnection(); 
     connection.ConnectionString = GetDefaultConnectionString(); 
     return connection; 
    } 

    public static DbConnection GetDBConnection() 
    { 
     DbProviderFactory factory = GetProviderFactory(); 
     return GetDBConnection(factory); 
    } 

    private static void ProcessParameters(
     DbProviderFactory factory, 
     DbCommand command, 
     string query, 
     object[] queryParameters) 
    { 
     if (queryParameters == null && queryParameters.Length == 0) 
     { 
      command.CommandText = query; 
     } 
     else 
     { 
      IFormatProvider formatProvider = CultureInfo.InvariantCulture; 
      DbCommandBuilder commandBuilder = factory.CreateCommandBuilder(); 
      StringBuilder queryText = new StringBuilder(query); 

      for (int index = 0; index < queryParameters.Length; index++) 
      { 
       string name = getParameterName(commandBuilder, index); 
       string placeholder = getParameterPlaceholder(commandBuilder, index); 
       string i = index.ToString("D", formatProvider); 

       command.Parameters.AddWithValue(name, queryParameters[index]); 
       queryText = queryText.Replace("{" + i + "}", placeholder); 
      } 

      command.CommandText = queryText.ToString(); 
     } 
    } 

    public static DataView GetDataView(string query, params object[] queryParameters) 
    { 
     DbProviderFactory factory = GetProviderFactory(); 

     using (DbConnection connection = GetDBConnection(factory)) 
     using (DbCommand command = connection.CreateCommand()) 
     { 
      command.CommandType = CommandType.Text; 
      ProcessParameters(factory, command, query, queryParameters); 

      DbDataAdapter adapter = factory.CreateDataAdapter(); 
      adapter.SelectCommand = command; 

      DataTable table = new DataTable(); 
      adapter.Fill(table); 
      return table.DefaultView; 
     } 
    } 
} 

С этой версии, теперь вы можете передать параметры просто и безопасно, не полагаясь на пользовательский код, чтобы попытаться блокировать инъекции SQL:

DataView dv = Database.GetDataView(
    "select mycolumn from my table where id = {0} and name = {1}", 
    1234, "Robert');DROP TABLE Students;--"); 

EDIT
Обновлен для поддержки параметров для разных поставщиков, с помощью this answer.

+0

FYI, SqlDataSource SelectCommand (и другие команды) не позволяют помещать точку с запятой в ваш запрос за пределами внутренней строки. Но я ценю ваш код. Вероятно, это что-то очень похожее на то, что SqlDataSource делает внутри. – mason

+0

@ msm8bball: Вы уверены? Я только что попробовал свой код с запросом '' select * из sys.databases, выберите * из sys.objects; "', и он выполнил обе команды. –

+0

Я пробовал его с System.Data.OracleClient и дает исключение во время выполнения. Теперь, когда я думаю об этом, я не могу вспомнить, что попробовал это от SQL Server или любого другого поставщика данных. Возможно, это специфичный для System.Data.OracleClient. – mason

Смежные вопросы