ASP.NET和SQL Server的自动完成功能

First of all, I know the

首先,我知道

AutoComplete feature should be done via an 自动完成功能应通过对某些Web服务/ Web API的 AJAX call to some web service/ web API, and then get and populate the response to the correct places or fields we wanted. AJAX调用来完成,然后获取并填充对我们想要的正确位置或字段的响应。

Things to consider:

注意事项:

1) What technologies to be used

1)使用什么技术

2) How to start

2)如何开始

3) Where to get the data

3)从哪里获取数据

4) How to populate the data

4)如何填充数据

5) Any other concerns

5)其他问题



1) What technologies to be used 1)使用什么技术

My friend didn't explain much on what program he is working on, but I do know he is using ASP.NET and SQL Server to construct his solution.

我的朋友对正在使用的程序没有太多解释,但是我知道他正在使用ASP.NETSQL Server构建其解决方案。

Since I need to use AJAX in order to pull the data, so I have done a search on Google and it returned with some examples and links. Eventually, I decided to use jqueryui's Autocomplete feature to build the solution for my friend.

由于我需要使用AJAX来提取数据,因此我在Google上进行了搜索,并返回了一些示例和链接。 最终,我决定使用jqueryui的自动完成功能为我的朋友构建解决方案。

2) How to start 2)如何开始

First of all, we need to create a .NET project, with C# as the preferred programming language.

首先,我们需要创建一个以C#作为首选编程语言的.NET项目。

Generally, you could create a ASP.NET Core or Web Application with .NET Framework project, and you could choose between a MVC or WebForm model as well.

通常,您可以使用.NET Framework项目创建ASP.NET Core或Web应用程序,也可以在MVC或WebForm模型之间进行选择。

3) Where to get the data 3)从哪里获取数据

In a common use case, we will probably grab the data from a Web service or Web API, which linked to a backend database, and the data returned will probably be in JSON or XML format.

在一个常见的用例中,我们可能会从链接到后端数据库的Web服务或Web API中获取数据,并且返回的数据可能采用JSON或XML格式。

For my friend's case, he doesn't have a ready-to-call interface available. Having said that, he has the full control over this web interface, database and able to decide what data format to be returned.

就我朋友而言,他没有可用的随时通话界面。 话虽如此,他拥有对该Web界面,数据库的完全控制权,并能够决定要返回的数据格式。

So, he needs to build the web service/ web API and develop some backend database scripting.

因此,他需要构建Web服务/ Web API并开发一些后端数据库脚本。

For database end, we need to know what table we are referring to, and to make the data retrieval easier, we probably can create a stored procedure, so at later stage, we can call it from the C# codes.

对于数据库端,我们需要知道要引用的表,并且为了简化数据检索,我们可能会创建一个存储过程,因此在以后的阶段,我们可以从C#代码中调用它。

For demo purposes, we can create the following table and stored procedure:

出于演示目的,我们可以创建下表和存储过程:

CREATE TABLE [dbo].[tblBorrowers](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](80) NULL,
    [address] [nvarchar](80) NULL,
    [phone] [nvarchar](30) NULL,
    [contact] [nvarchar](30) NULL,
    [email] [nvarchar](40) NULL,
    [website] [nvarchar](255) NULL,
    [tic_borrower] [nvarchar](20) NULL,
 CONSTRAINT [PK_tblBorrowers] PRIMARY KEY CLUSTERED
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO


CREATE PROCEDURE [dbo].[Sp_GetBorrowsers]
(
    @term NVARCHAR(30)
)
AS
BEGIN
    SET NOCOUNT ON;
   
    SELECT name label, name value, *
    FROM tblBorrowers
    WHERE [name] LIKE '%' + @term + '%'
    ORDER BY [name];
END
GO 

We could insert some dummy data into the table:

我们可以在表中插入一些虚拟数据:

SET IDENTITY_INSERT [dbo].[tblBorrowers] ON
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (1, N'Name 1', N'Address 1', N'Phone 1', N'Contact 1', N'Email 1', N'Website 1', N'A')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (2, N'Name 2', N'Address 2', N'Phone 2', N'Contact 2', N'Email 2', N'Website 2', N'B')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (3, N'Name 3', N'Address 3', N'Phone 3', N'Contact 3', N'Email 3', N'Website 3', N'C')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (4, N'Tan', N'dummy'' addr'' xx', N'phone 4', N'91234567', N'test@here.com', N'web 4', N'D')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (5, N'Andy', N'du<b>mmy " \ > addr DGs dd', N'phone 5', N'61234567', N'gtst@h.com', N'web 5', N'A')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (6, N'David', N'dummy addr dgo', N'phone 6', N'11111111', N'em@here.com', N'web 6', N'C')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (7, N'Dan', N'dummy addr Hds', N'Phone 7', N'22222222', N'sgd@h.com', N'web 7', N'B')
GO
INSERT [dbo].[tblBorrowers] ([id], [name], [address], [phone], [contact], [email], [website], [tic_borrower]) VALUES (8, N'Ant', N'dummy addr sdds', N'Phone 8', N'33333333', N'dgd@GS', N'web 8', N'C')
GO
SET IDENTITY_INSERT [dbo].[tblBorrowers] OFF
GO 

For the web service/ web API, we could create an ASP.NET Core Web API or WCF project for this purpose, but due to the fact that I need to show this sample project to my friend pretty quickly, so I have created a simple Generic Handler for this purpose.

对于网络服务/网络API,我们可以创建一个 为此目的,使用ASP.NET Core Web APIWCF项目,但是由于我需要将该示例项目Swift展示给我的朋友,因此我为此创建了一个简单的通用处理程序。

We name the file as posting.ashx

我们将文件命名为posting.ashx

public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/json";


            string term = context.Request.Form["term"];
            try
            {
                if (term == null)
                {
                    context.Response.Write("Invalid Parameter(s)");
                }
                else
                {
                    //Trim what to search
                    term = term.Trim();


                    //Read connection string
                    String connstring = ConfigurationManager.ConnectionStrings["conn"].ConnectionString;


                    //Establish connection and grab data
                    using (SqlConnection conn = new SqlConnection(connstring))
                    {
                        conn.Open();
                        using (SqlCommand cmd = new SqlCommand("Sp_GetBorrowsers", conn))
                        {
                            cmd.CommandType = CommandType.StoredProcedure;
                            cmd.CommandTimeout = 30;


                            cmd.Parameters.Add("@term", System.Data.SqlDbType.NVarChar).Value = term;
                           
                            using (SqlDataReader r = cmd.ExecuteReader())
                            {
                                //Convert data reader to json
                                var obj = Serialize(r);
                                string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
                                context.Response.Write(json);
                            }
                        }


                    }
                }
            }
            catch (Exception)
            {
                context.Response.Write("Error Processing Request");
            }
        }


public IEnumerable<Dictionary<string, object>> Serialize(SqlDataReader reader)
        {
            var results = new List<Dictionary<string, object>>();
            var cols = new List<string>();
            for (var i = 0; i < reader.FieldCount; i++)
                cols.Add(reader.GetName(i));


            while (reader.Read())
                results.Add(SerializeRow(cols, reader));


            return results;
        }
        private Dictionary<string, object> SerializeRow(IEnumerable<string> cols,
                                                        SqlDataReader reader)
        {
            var result = new Dictionary<string, object>();
            foreach (var col in cols)
                result.Add(col, reader[col]);
            return result;
        } 

What interest thing part from C# codes above is to serialize SqlDataReader object to JSON.

上面的C#代码有趣的是将SqlDataReader对象序列化为JSON

4) How to populate the data 4)如何填充数据

Now, let's try construct a simple WebForm.

现在,让我们尝试构建一个简单的WebForm。

What important for us is to create the form elements, such as:

对我们来说重要的是创建表单元素,例如:

<table>
                <tr>
                    <th colspan="3" class="auto-style4">Borrower Detail</th>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="name">Name</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <input id="name"></td>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="address">Address</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <input id="address"></td>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="phone">Phone</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <input id="phone"></td>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="contact">Contact</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <input id="contact"></td>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="email">Email</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <input id="email"></td>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="website">Website</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <input id="website"></td>
                </tr>
                <tr>
                    <td class="auto-style3">
                        <label for="tic_borrower">TIC Borrower</label></td>
                    <td class="auto-style2">:</td>
                    <td class="auto-style1">
                        <select id="tic_borrower">
                            <option value=""></option>
                            <option value="A">A</option>
                            <option value="B">B</option>
                            <option value="C">C</option>
                            <option value="D">D</option>
                        </select></td>
                </tr>
                <tr>
                    <td class="auto-style3">&nbsp;</td>
                    <td class="auto-style2">&nbsp;</td>
                    <td class="auto-style1">
                        <input id="reset" type="reset" value="reset" /></td>
                </tr>
            </table>

and then we need to include some style sheets and JavaScript links in the head section:

然后我们需要在头部添加一些样式表和JavaScript链接:

<head runat="server">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test</title>
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">


    <style>
        .ui-autocomplete-loading {
            background: url(http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/smoothness/images/ui-anim_basic_16x16.gif) no-repeat right center
        }


        table, th, td {
            border: 1px solid black;
            width: 500px;
            height: 50px;
        }


        .auto-style1 {
            width: 100px;
        }


        .auto-style2 {
            width: 16px;
        }


        .auto-style3 {
            width: 136px;
        }


        .auto-style4 {
            text-align: left;
        }
    </style>
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script>
        $(function () {
            function populate(item) {
                $('#address').val(item.address);
                $('#phone').val(item.phone);
                $('#contact').val(item.contact);
                $('#email').val(item.email);
                $('#website').val(item.website);
                $('#tic_borrower').val(item.tic_borrower);
            }


            $("#name").autocomplete({
                source: function (request, response) {
                    $.ajax({
                        url: "posting.ashx",
                        method: "POST",
                        dataType: "json",
                        data: {
                            term: request.term
                        },
                        success: function (data) {
                            response(data);
                        }
                    });
                },
                minLength: 2,
                select: function (event, ui) {
                    populate(ui.item);
                }
            });
        });


        $(document).ready(function () {
            $("#name").focus();


            $("#reset").click(function () {
                $("#name").focus();
            });
        });
    </script>
</head> 

Let me try to explain some of the important part from codes above.

让我尝试从上面的代码中解释一些重要的部分。

a) style .ui-autocomplete-loading a)样式.ui-autocomplete-loading
.ui-autocomplete-loading {
            background: url(http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/smoothness/images/ui-anim_basic_16x16.gif) no-repeat right center
        }

We use it so that it will generate a small loading icon while the data is loading.

我们使用它,以便在加载数据时它会生成一个小的加载图标。

b) Call the web service/ web API b)调用Web服务/ Web API
$("#name").autocomplete({
                source: function (request, response) {
                    $.ajax({
                        url: "posting.ashx",
                        method: "POST",
                        dataType: "json",
                        data: {
                            term: request.term
                        },
                        success: function (data) {
                            response(data);
                        }
                    });
                },
                minLength: 2,
                select: function (event, ui) {
                    populate(ui.item);
                }
            }); 

The codes above will tell us:

上面的代码将告诉我们:

  • What URL to post the request

    发布请求的URL
  • What method to be used (POST, GET, etc)

    使用什么方法(POST,GET等)
  • What data type to be returned (JSON, XML, etc)

    要返回的数据类型(JSON,XML等)
  • What action to be done once we got a success response (in this case, we are calling the function: "populate" to generate the output)

    收到成功响应后应执行什么操作(在这种情况下,我们正在调用函数“填充”以生成输出)
  • What is the minimum length of search characters (in this case, at least 2 chars need to be entered to trigger the autocomplete posting)

    搜索字符的最小长度是多少(在这种情况下,至少需要输入2个字符才能触发自动完成发布)
5) Any other concerns 5)其他问题

It is always good and maintain a best practice to "ask questions", and not to simply copy and paste some solutions from elsewhere and apply it directly into our own project without thinking the risk and impact of it.

最好总是保持“提问”的最佳实践,而不是简单地从其他地方复制和粘贴一些解决方案,然后直接将其应用到我们自己的项目中,而无需考虑其风险和影响。

a) Data encoding? a)数据编码?

Just want to make sure the data populating is in good form and didn't break up the form.

只是要确保填充的数据格式正确,并且不会破坏表格。

We can test this by doing a search for "Tan" and "Andy".

我们可以通过搜索“ Tan”和“ Andy”进行测试。

As a result, it seems that the code is handling the encoding well.

结果,似乎代码可以很好地处理编码。

Hence, it also mean a valid JSON should be returned from the respective web service/ web API.

因此,这也意味着应该从相应的Web服务/ Web API返回有效的JSON。

b) The necessity of Multiple Posting? b)是否需要多次过帐?

Someone may ask, do we need to have the separate posting since the first posting is grabbing all matched data back from the response?

有人可能会问,由于第一个发布从响应中获取了所有匹配的数据,我们是否需要单独发布?

For example, if we do a search on "na", the following result will be returned:

例如,如果我们搜索“ na”,将返回以下结果:

[
  {
    "label": "Name 1",
    "value": "Name 1",
    "id": 1,
    "name": "Name 1",
    "address": "Address 1",
    "phone": "Phone 1",
    "contact": "Contact 1",
    "email": "Email 1",
    "website": "Website 1",
    "tic_borrower": "A"
  },
  {
    "label": "Name 2",
    "value": "Name 2",
    "id": 2,
    "name": "Name 2",
    "address": "Address 2",
    "phone": "Phone 2",
    "contact": "Contact 2",
    "email": "Email 2",
    "website": "Website 2",
    "tic_borrower": "B"
  },
  {
    "label": "Name 3",
    "value": "Name 3",
    "id": 3,
    "name": "Name 3",
    "address": "Address 3",
    "phone": "Phone 3",
    "contact": "Contact 3",
    "email": "Email 3",
    "website": "Website 3",
    "tic_borrower": "C"
  }
] 

Is there a scenario that we wish to "protect" the data above from being exposed to end users? and only provide the necessary details, such as "Label", "Value" and "Id" to be shown on the result drop down list?

我们是否有一种希望“保护”以上数据不暴露给最终用户的方案? 仅提供必要的详细信息,例如要在结果下拉列表中显示的“标签”,“值”和“ ID”?

Since now we only sent one request to the web service/ web API, other details such as "Name", "Address", "Phone", etc are being returned as well. Shall we create the second request call based on "Id" and grab that details so that such data are not being exposed at the first place?

从现在开始,我们只向Web服务/ Web API发送了一个请求,其他详细信息(如“名称”,“地址”,“电话”等)也将返回。 我们是否应该基于“ Id”创建第二个请求调用并获取详细信息,以使此类数据不会在一开始就暴露出来?

As far as what I consider, I would think a multiple posting architecture is not necessary since we are doing a wildcard searching. Those data should be classified as "not sensitive" despite the fact it may contain Personally identifiable information (PII).

就我而言,我认为多发布架构不是必需的,因为我们正在进行通配符搜索 。 尽管这些数据可能包含个人身份信息(PII),但仍应将其分类为“不敏感”。

If there is some data which is classified to be (highly) "sensitive", we should discourage it and avoid the implementation with autocomplete feature.

如果有一些数据被分类为(高度)“敏感”,我们应该劝阻它,并避免使用自动完成功能。

We could refer to Open Web Application Security Project (OWASP) for such considerations.

我们可以参考 出于此类考虑,请打开Web应用程序安全项目(OWASP)

翻译自: https://www.experts-exchange.com/articles/34350/AutoComplete-feature-with-ASP-NET-and-SQL-Server.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值