2012-05-29 53 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