【问题标题】:Search with autocomplete and Ajax使用自动完成和 Ajax 进行搜索
【发布时间】:2012-06-03 19:28:51
【问题描述】:

我想像他们一样从谷歌搜索。

我已经做到了这一点,我可以使用网络服务在我的文本框中显示数据库中的所有数据。这是我的代码:

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? 我希望你能理解我的问题。我的英语不太好...

感谢您的帮助!

【问题讨论】:

    标签: c# asp.net sql ajax autocomplete


    【解决方案1】:

    为什么不直接将项目名称作为参数而不是 probject ID 传递?如果您使用的是 Response.Redirect 我假设用户从选择列表中选择一个项目,并且后面的代码处理某种事件:

        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
        }
    

    另外使用参数化查询否则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();
        }
    

    【讨论】:

    • 非常感谢您提供这个非常有用的答案!真的帮了我
    • @GarethD 你假设项目名称是唯一的,如果项目名称在这里唯一,为什么 OP 需要 ID 字段!
    • @Damith 这很好,但是如果项目名称不是唯一的,用户如何知道自动完成中出现的 2 个项目中的哪一个?
    • @GarethD 我也这么认为。在我的门户中,我很幸运,所有项目都有一个唯一的名称,因此您的解决方案对我来说很好。但是,如果有人有“更清洁”的解决方案,我会非常感兴趣。顺便说一句:感谢“参数化查询”的解释。我以前从未想过他的安全问题(幸运的是它是一个内部网应用程序)。
    • 我没有尝试过@Damith 在他的回答中提到的 Ajax 工具包方法,但据我所知,我会说这是最好的解决方案,而不是构建自己的自定义解决方案。我实际上赞成他的回答,因为我认为它比我的要好。欢迎您提供有关参数化查询的建议,即使在应使用它们的 Intranet 应用程序上,除了 SQL 注入之外,还有更多使用它们的原因(类型化参数,不会因字符串截断而丢失数据,以及更易读的代码)。跨度>
    猜你喜欢
    • 1970-01-01
    • 2012-01-14
    • 2015-04-10
    • 2012-07-29
    • 2019-06-28
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多