65.9K
CodeProject 正在变化。 阅读更多。
Home

Amazon Explorer - ASP.NET 与 Amazon Web Service 的一次冒险

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (25投票s)

2003年8月28日

CPOL

12分钟阅读

viewsIcon

250428

downloadIcon

6027

创建一个 ASP.NET 应用程序,使用 Amazon Web Service 搜索 Amazon 目录。

Sample Image - amazonportal.jpg

引言

.NET Framework 和 Web Services 问世以来,我听过许多关于这两种技术有趣而精彩的应用。然而,直到自己亲手尝试,你才能真正体会到它的价值。我将我的一个想法应用到了这些技术上,并且尝试后发现效果非常好,实现起来也并不困难。现在,我将我的第一个 ASP.NET 应用程序——Amazon Explorer 介绍给大家。

简而言之,Amazon Explorer 是一个 ASP.NET 应用程序,它允许用户通过使用 Amazon Web Service(3.0 版) 来搜索 Amazon 的任何商品目录。

如何设置/安装

我在 Visual Studio .NET 2002 中使用了一个 Web Setup 项目来创建 Amazon Explorer 的安装程序。只需运行 AmazonPortalSetup.msi 文件并按照说明进行操作即可。您需要运行 IIS。该安装程序会在 IIS 中创建一个虚拟目录,并将文件(源文件、DLL 等)复制到您的硬盘。或者,您也可以从 Visual Studio 模板中创建一个 ASP.NET 应用程序,然后从提供的 zip 文件中复制源文件。

冒险 - 学到的教训

在开发这个应用程序的过程中,我学习到了 .NET Framework 提供的各种功能和能力,这些功能可以减轻 Web 开发的痛苦,并轻松使用 Web Services。在这一部分,我将通过应用程序的功能来介绍 ASP.NET 和 .NET Framework 的各项有用功能。

用户界面 (UI)

Amazon Explorer 的界面设计简洁,以一种优雅而简单的方式收集用户的所有必要输入。下面是应用程序首次启动时的截图,以及应用程序显示先前搜索结果的截图。

图 01:初始应用程序界面

图 02:结果页面

应用程序的生命周期中,您将看到这两个屏幕。唯一例外是当搜索过程中发生错误时,此时您将看到显示相应的错误消息。界面非常简单,只包含几个 ASP.NET Web Form 控件。当我刚开始开发这个应用程序时,我使用了网页表单控件的普通 HTML 版本,即下拉列表、文本框和提交按钮。

这里的问题是,在我的应用程序默认使用的表单提交过程中,我无法保留控件的值!唉……但很快,Web Forms 就来拯救我了 :)。我发现 Web Form 控件默认情况下可以在提交之间保留其值。我的第一个想法是……太棒了!从那时起,我将所有普通的 HTML 控件替换为了它们对应的 Web Form 控件版本。下面您可以看到在 Visual Studio .NET IDE 中的界面截图。

图 03:Visual Studio .NET IDE -- 设计模式

在上面的图 03 中,您会注意到数字 1 - 3。这些区域中的每一个都包含构成整个 Amazon Explorer 应用程序的不同控件或组件。

区域 1:DataGrid 组件

DataGrid 组件用于显示最终用户搜索的结果。这个组件非常适合这项工作,因为它可以绑定到各种数据源。数据源的使用完全取决于您的需求,但在本场景中,我使用了一个 DataSet。搜索的数据源是通过 Amazon Web Service 填充的。

区域 2:下拉列表、文本框和提交按钮

下拉列表用于方便用户选择搜索参数,这些参数有助于在 Amazon 目录中搜索商品。一个下拉列表用于允许用户选择他们认为商品所在的类别。另一个列表允许用户指定搜索结果在结果页面上显示的最多数量。

文本框用于获取用户的自由输入(即键入的输入)。具体来说,我想获取用户想要搜索的商品名称。其他文本框用于收集价格范围值,以便用户可以按价格范围搜索商品。不幸的是,Amazon Web Service 不支持通过 SOAP 进行价格范围搜索,但支持通过常规 HTTP 请求进行。未来当支持 SOAP 时,这些文本框将在后端使用,但目前我将它们保留用于显示 ASP.NET Web Form 控件的验证功能。

区域 3:验证控件

验证控件用于在表单值用于提交搜索到 Amazon Web Service 之前验证用户输入。这些控件的简单程度让我感到惊讶!通常在过去,我们需要编写 JavaScript 来进行输入验证和校验。虽然网上有很多可重用的代码,但能够简单地指定验证规则,然后让 .NET 来处理其余部分,这仍然很棒。嗯,正如我过去听到的那样,有求必应。

为了在这里执行输入验证,我使用了 .NET 的 CompareValidator Web Form 控件,它非常方便地允许您通过在控件的属性中选择它们来指定要比较的项。多么方便啊!除了这个方便的功能,要指定错误消息,您只需在属性字段中键入它,瞧,您的 Web Form 就有了非常漂亮而简单的输入验证。

图 04:CompareValidator 属性表

这基本上完成了我的用户界面。唯一的额外部分是我使用其属性表更改了 DataGrid 的格式,为 DataGrid 显示提供了一个漂亮的配色方案。大家都应该还记得 Microsoft Word 的 Table AutoFormat 选项中的这个配色方案。

后端 (Code behind)

现在我们有了 UI,就需要一些代码来处理来自 UI 的输入,通过向最终用户显示一些结果来获得有意义的输出。在这个项目中,我选择的实现语言是 C#。为什么?嗯,.NET Framework 允许我用它支持的 30 多种语言中的任何一种来实现这个应用程序,但出于历史原因,我喜欢我的花括号和分号 :)

最初我开始这个项目时,以为会写很多代码。天哪,我错了。当用户点击“搜索 Amazon”按钮时,Amazon Explorer 中的操作就开始了。Web Form 被发送回服务器,在那里收集输入并通过 Amazon Web Service 进行处理,然后返回一些结果给 Web Form 以供用户显示。这就是它的全部内容,简洁明了。从收集文本框输入到处理搜索按钮点击的所有代码都在后端。除此之外,我们还有 .NET 提供的几个很棒的功能。

数据收集与缓存

Amazon Explorer 的主要目的是显示最终用户搜索的结果。可以想象,有时会有大量结果。解决这个问题的一个好方法是有一个分页机制,一次显示“x”个结果。DataGrid 提供了此功能,只需选择几个控件的属性字段即可。涉及的字段是 AllowPagingPageSize。还请注意,您可以为 DataGrid 实现自己的自定义分页解决方案,但我只是想要简单的分页,所以选择了属性选择。除了这些属性选择之外,还需要为 DataGrid 在用户选择与当前页面不同的页面时触发的 PageIndexChanged 事件创建一个事件处理程序。

1: private void gridAmazonResults_PageIndexChanged
                    (object source, DataGridPageChangedEventArgs e)
2: {
3:    gridAmazonResults.CurrentPageIndex = e.NewPageIndex;
4:    dsetAmazonReponse = (DataSet)Cache[AMAZON_CACHE_NAME];
5:    gridAmazonResults.DataSource = dsetAmazonReponse;
6:    gridAmazonResults.DataBind();
7: }

在此需要注意的是,所做的所有操作是更改 DataGrid 中的当前页面索引(第 3 行),然后将 DataGrid(第 6 行)绑定到缓存的 DataSet(第 4-5 行)。

ASP.NET 中的缓存非常简单,在可用性和数据处理方面显示出显著的速度提升。最初,当我进行不带缓存的分页时,每一次页面更改都需要访问 Amazon Web Service 来更新页面,即使我已经有了应用程序中使用的 DataSet 中的所有信息。当然,您可以想象由此带来的性能问题。我之所以在应用程序中使用缓存,除了性能提升之外,是因为当用户进行搜索时,最好让他能够查看搜索时返回的所有结果。只有当用户点击“搜索 Amazon”按钮时,我们才会再次访问 Amazon Web Service,这表示他想进行一个“全新”的搜索,而不是查看他所有的搜索结果。

1: private void btnSubmit_Click(object sender, System.EventArgs e)
2: {
3:   Cache.Remove(AMAZON_CACHE_NAME);
4:   dsetAmazonReponse = (DataSet)Cache[AMAZON_CACHE_NAME];
5:
6:   if( dsetAmazonReponse == null )
7:   {
8:      dsetAmazonReponse = new DataSet();
9:      dsetAmazonReponse.Tables.Add("AmazonResults");
10:     dsetAmazonReponse.Tables["AmazonResults"].Columns.Add("Preview");
11:     dsetAmazonReponse.Tables["AmazonResults"].Columns.Add("Name");
12:     dsetAmazonReponse.Tables["AmazonResults"].Columns.Add("Our Price");
13:     dsetAmazonReponse.Tables["AmazonResults"].Columns.Add("List Price");
14:     dsetAmazonReponse.Tables["AmazonResults"].Columns.Add("Catalog");
15:        
16:     ProcessSearchRequest();
17:     Cache[AMAZON_CACHE_NAME] = dsetAmazonReponse;
18:   }
19:   dsetAmazonReponse = (DataSet)Cache[AMAZON_CACHE_NAME];
20:   gridAmazonResults.DataSource = dsetAmazonReponse;
21:   gridAmazonResults.DataBind();
22: }

在上面的代码片段中,我们看到了当用户请求“全新”搜索时正在发生的事情。我们首先移除缓存中当前的 DataSet(第 3-4 行),然后获取一个新的 DataSet 并创建我们用来设置从 Amazon Web Service 获取的数据的表(第 6-18 行)。在 Amazon Web Service 执行完请求后,我们将 DataGrid 重新绑定到 DataSet,该 DataSet 现在包含我们想要以一种良好格式化的方式在网格中显示给用户的数据(第 19-21 行)。

应用程序配置

与大多数应用程序一样,Amazon Explorer 也有某些可以配置的特性,以影响应用程序的运行方式。例如,有一种配置允许应用程序在代理服务器后面运行。我想要一个机制,允许我更改一个标志或类似的设置,以便 Amazon Explorer 可以在代理服务器后面工作,而无需我重新编译代码以及所有那些有趣的事情。同样,.NET Framework 再次帮助了我。

Microsoft 有一种机制,现在允许开发人员将他们的应用程序特定设置放在他们称之为 .config 文件中。实际上,这些文件与 .ini 文件非常相似,唯一的区别是它们是 XML 格式的。通过这个方便的功能,我能够指定一些设置,这些设置会在应用程序分发到不同的域、机器和开发人员时发生变化。

<appSettings>
   <add key="SetProxy" value="off" />
   <add key="ProxyIP" value="111.2.3.4" />
   <add key="ProxyPort" value="8080" />
</appSettings>

在上面,我能够在 Web.config 文件中指定一些我认为在应用程序中是动态的属性。代理信息允许我通过编辑 .config 文件来更改我所在位置的代理信息。当用户再次点击“搜索 Amazon”按钮时,将根据 .config 文件中的 SetProxy 字段的值来使用代理。

1: private void Page_Load(object sender, System.EventArgs e)
2: {
3:   if( ConfigurationSettings.AppSettings[CONFIG_PROXY_NAME] == "on" )
4:    SetProxy(ConfigurationSettings.AppSettings[CONFIG_PROXY_IPVALUE],
5:      Convert.ToInt32(ConfigurationSettings.
6:                   AppSettings[CONFIG_PROXY_PORTVALUE]));
7: }

在上面的代码的第 3 行,您可以看到我们如何从 Web Form 代码中访问 .config 文件中指定的设置。Configuration 对象中的 AppSettings 集合包含我们在基于 XML 的 .config 文件中的 <appSettings> 元素中指定的所有键值字段。访问设置值就像索引 AppSettings 数组一样简单,瞧,您的动态设置就已加载到您的应用程序中。

Amazon Web Service

Amazon Web Service 是该应用程序的真正主力。没有它,我们就没有结果可显示。Amazon Web Service API 非常简单,只需几行代码即可让开发人员发出查询并接收项目集合。以下是执行 Amazon 目录通用关键字搜索的代码示例。

1: AmazonSearchService amazonSrch = new AmazonSearchService();
2: KeywordRequest kwdReq = new KeywordRequest();
3:
4: kwdReq.devtag = "1010101010";
5: kwdReq.keyword = "Beenie Man";
6: kwdReq.type = "heavy";
7: kwdReq.mode = "music";
8:
9: ProductInfo prodMfg = amazonSrch.KeywordSearchRequest(kwdReq);

这三个关键对象是 AmazonSearchServiceKeywordRequestProductInfo。仅从对象名称就可以看出它们在整个体系中的作用。AmazonSearchService 是我们用来连接 Amazon 提供的 Web Service 的。通过此对象,我们可以执行 API 提供的各种类型的搜索/请求。其中一种搜索/请求类型是 KeywordRequest,它允许我们通过提供简单的关键字来搜索 Amazon 目录,这与搜索 Google 等常规网络搜索引擎非常相似。API 提供的各种请求中的每一种都会返回有关其在目录中找到的商品的一些产品信息。这些信息封装在 ProductInfo 对象中。ProductInfo 对象本身包含一个 Details 对象的集合。集合中的每个 Details 对象 - 一个数组 - 包含在目录中找到的商品的具体信息。我将留给您自己去发现这些具体信息,因为内容非常多!

每次我们获取产品信息时,我们都希望使其可供我们的 DataGrid 使用,以便在用户查看结果时可以显示给最终用户。我们通过将信息添加到我们的 DataSet 来实现这一点,该 DataSet 稍后将绑定到 DataGrid。

1: private void AddToDataSet(ProductInfo newProducts)
2: {
3:    DataRow newRow;
4:
5:    for( int i = 0; i < newProducts.Details.Length; i++ )
6:    {
7:       newRow = dsetAmazonReponse.Tables["AmazonResults"].NewRow();
8:
9:       newRow["Our Price"] = newProducts.Details[i].OurPrice;
10:      newRow["List Price"] = newProducts.Details[i].ListPrice;
11:      newRow["Catalog"] = newProducts.Details[i].Catalog;
12:
13:      dsetAmazonReponse.Tables["AmazonResults"].Rows.Add(newRow);
14:   }
15: }

如上所示,每个新项目都放在我们的 DataSet 的新行中(第 13 行),并且行的列用来自 Details 对象的实际数据填充(第 9-11 行)。在此方法结束时,我们已经收集了所有需要显示给用户的产品信息。当您查看实际代码时,您会看到可以根据需要修改和格式化数据的方法。上面的代码只是一个简单的示例。

结论

从构思到实现,这个应用程序花费了大约一周半的时间(断断续续地开发),并且在此之前我没有 ASP.NET 的任何经验。对我来说,这相当令人印象深刻,并且告诉我微软在帮助开发人员快速而高效地完成工作方面迈出了重要一步。我个人现在对 ASP.NET 和 Web Services 产生了浓厚的兴趣,并期待着与这两种技术进行更多的工作。正如您所见,Amazon Web Service API 非常简单且易于使用,ASP.NET 本身也并不难使用,因为它通过优雅的控件和组件在简单的界面中提供了强大的功能。

资源

以下是我在开发和研究此应用程序过程中发现非常有用的资源列表。

修订

  • 08-28-2003:
    • 原始文章提交
© . All rights reserved.