2012-05-29 2 views
2

Я хочу сделать поиск, подобный им, из google.Поиск с автозаполнением и Ajax

Я сделал это так далеко, что могу показать все данные из базы данных в своем текстовом поле с помощью webservice. Вот мой код:

Webform.aspx

<%--**Start Search**--%> 
<asp:ScriptManager ID="ScriptManager1" runat="server"> 
    <Services><asp:ServiceReference Path="~/WebService.asmx" /></Services> 
</asp:ScriptManager> 
<%--Search-Textbox--%> 
<asp:TextBox runat="server" ID="txtSearchInput" Width="100%" /> 
<asp:Button ID="btnSearch" runat="server" Text="Suche" onclick="btnSearch_Click" /> 
<%--Autocomplete (Ajax)--%> 
<asp:AutoCompleteExtender ID="AutoComplete1" runat="server" TargetControlID="txtSearchInput" 
    ServiceMethod="GetNames" ServicePath="~/WebService.asmx" MinimumPrefixLength="1" 
    EnableCaching="true" CompletionInterval="1000" CompletionSetCount="20"> 
</asp:AutoCompleteExtender> 
<%--**End Search**--%> 

Webservice.asmx

[WebMethod] 
public string[] GetNames(string prefixText, int count) 
{ 
    List<string> items = new List<string>(count); 
    DataSet ds = new DataSet(); 

    string cs = ConfigurationManager.ConnectionStrings["CSLinker"].ConnectionString; 

    using (SqlConnection connection = new SqlConnection(cs)) 
    { 
     string sql = "SELECT Name FROM tabProjects WHERE Name LIKE '" + prefixText + "%' UNION all SELECT Name FROM tabLinks WHERE Name LIKE '" + prefixText + "%'"; 
     SqlDataAdapter adapter = new SqlDataAdapter(); 
     adapter.SelectCommand = new SqlCommand(sql, connection); 
     adapter.Fill(ds); 
    } 

    foreach (DataRow dr in ds.Tables[0].Rows) 
    { 
     items.Add(dr["Name"].ToString()); 
    } 
    return items.ToArray(); 
} 

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

Спасибо за помощь!

ответ

1

Почему бы просто не передать название проекта в качестве параметра, а не идентификатора объекта? Если вы используете Response.Redirect Я предполагаю, что пользователь выбирает проект из списка выбора и код за ручки somekind события:

public void onProjectSelected() 
    { 
     string cs = ConfigurationManager.ConnectionStrings["CSLinker"].ConnectionString; 
     string projectName = txtSearchInput.Text; 
     int projectID = 0; 
     using (SqlConnection connection = new SqlConnection(cs)) 
     { 
      using (SqlCommand command = new SqlCommand("SELECT ProjectID FROM TabProjects WHERE Name = @Name", connection)) 
      { 
       command.Parameters.Add(new SqlParameter("@Name", SqlDbType.VarChar, 50)).Value = projectName; 
       connection.Open(); 
       if (int.TryParse(command.ExecuteScalar().ToString(), out projectID)) 
       { 
        Response.Redirect(string.Format("?ProjectID={0}", projectID)); 
       } 
       connection.Close(); 
      } 
     } 
     //Handle project not found events here 
    } 

Также USE PARAMATERISED ЗАПРОСЫ иначе SQL Injection может испортить ваш день!

Если бы я напечатал «Это тест» в вашем текстовом поле, вы получите недопустимый оператор SQL, так как апостроф, который я использовал, приведет к следующему SQL.

SELECT Name FROM tabProjects WHERE Name LIKE 'It's a test%' 

Что явно не будет работать и не будет отличным пользовательским интерфейсом для тех, кто использует ваш сайт. Более серьезно, хотя, если бы я набрал текстовое поле на вашей странице '; DROP TABLE TabProjects --, вы можете найти, опираясь на разрешения, назначенные для строки подключения CSLinker, что у вас больше нет таблицы tabProjects, поскольку это SQL-код, который запущен:

SELECT Name FROM tabProjects WHERE Name LIKE ''; DROP TABLE tabProjects -- %' 

Вы должны использовать что-то вроде этого для вашего веб-метода:

[WebMethod] 
    public string[] GetNames(string prefixText, int count) 
    { 
     List<string> items = new List<string>(); 
     string cs = ConfigurationManager.ConnectionStrings["CSLinker"].ConnectionString; 
     using (SqlConnection connection = new SqlConnection(cs)) 
     { 
      using (SqlCommand command = new SqlCommand("SET ROWCOUNT @Count SELECT Name FROM TabProjects WHERE Name LIKE @Name + '%'", connection)) 
      { 
       command.Parameters.Add(new SqlParameter("@Name", SqlDbType.VarChar, 50)).Value = prefixText; 
       command.Parameters.Add(new SqlParameter("@Count", SqlDbType.Int, 8)).Value = count; 
       connection.Open(); 
       using (SqlDataReader reader = command.ExecuteReader()) 
       { 
        while (reader.Read()) 
        { 
         items.Add(reader.GetString(0)); 
        } 
       } 
       connection.Close(); 
      } 
     } 
     return items.ToArray(); 
    } 
+0

спасибо большое за это очень полезный ответ! Действительно помог мне – Luca

+0

@GarethD вы предполагаете название проекта уникальным, если имя проекта уникально здесь, почему OP хочет ID поле! – Damith

+0

@Damith Это хороший момент, однако если имя проекта не уникально, как пользователь узнает, какой из двух проектов, входящих в автозаполнение, выбрать? – GarethD