2012-05-29 52 views
2

我想從谷歌搜索他們。使用autocomplete和Ajax搜索

我已經做到了這一點,我可以使用web服務在我的文本框中顯示數據庫中的所有數據。這就是我的代碼:

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(); 
} 

我現在的問題是,我只有從數據庫的名稱。但爲了搜索,我還需要ID。有人可以說我,我怎麼也可以查詢ID而不顯示它在文本形式? 我希望你能理解我的問題。我的英語不太好......

感謝您的幫助!

回答

1

爲什麼不只是傳遞項目名稱作爲參數而不是探測ID?如果您使用的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 
    } 

而且使用PARAMATERISED QUERIES否則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 -- %' 

你應該使用類似這樣您的Web方法:

[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這是一個很好的觀點,但是如果項目名稱不是唯一的,用戶將如何知道自動完成中出現的2個項目中的哪一個可以選擇? – GarethD