当前位置: 首页 > 文章教程  > 计算机与互联网 > 网络编程

10.7技术解惑

8/31/2020 9:56:04 PM 人评论

10.7技术解惑

在ASP.NET程序中,QueryExtender控件是一个过滤控件,可以对数据库中的数据进行筛选。对于创建数据驱动的网页的开发人员,一项十分常见的任务就是筛选数据。该任务的传统实现执行方法是在数据源控件中生成Where子句。这种方法十分复杂,而且在某些情况下,通过Where语法无法充分利用基础数据库的全部功能。为了简化筛选操作,ASP.NET 4.5中增加了QueryExtender控件。

在开发应用中,可以将QueryExtender控件添加到EntityDataSource 或 LinqDataSource 控件中,以筛选这些控件返回的数据。QueryExtender控件依赖于LINQ,但用户无需了解如何编写LINQ查询即可使用该查询扩展程序。QueryExtender 控件支持多种筛选选项,如表10-1所示。

表10-1 QueryExtender的筛选选项

术  语

定  义

SearchExpression

搜索一个或多个字段中的字符串值,并将这些值与指定的字符串值进行比较。

RangeExpression

在一个或多个字段中搜索由一对值指定的范围内的值

PropertyExpression

对指定的值与字段中的属性值进行比较。如果表达式的计算结果为True,则返回所检查的数据

OrderByExpression

按指定的列和排序方式对数据进行排序

CustomExpression

调用一个函数,用于定义页面中的自定义筛选器

筛选操作通过仅显示满足指定条件的记录,从数据源中排除数据。通过筛选,可以在不影响数据集中的数据的情况下以多种方式查看这些数据。

筛选通常要求用户创建Where子句,以应用于查询数据源的命令。但是,LinqDataSource控件的Where属性并不公开LINQ中提供的全部功能。为了更便于筛选数据,ASP.NET 4.5提供了QueryExtender控件,该控件可通过声明性语法从数据源中筛选出数据。使用QueryExtender控件有以下优点。

(1)与编写Where子句相比,可提供功能更丰富的筛选表达式。

(2)提供一种LinqDataSource和EntityDataSource控件均可使用的查询语言。例如,如果将QueryExtender与这些数据源控件配合使用,则可以在网页中提供搜索功能,而不必编写特定于模型的Where子句或eSQL语句。

(3)可以与LinqDataSource或EntityDataSource 控件配合使用,或与第三方数据源配合使用。

(4)支持多种可单独和共同使用的筛选选项。

从ASP.NET 4.0开始,ASP.NET提供了新的并行库以及新的并行编程模式和编程思维方式。很多读者可能觉得在日常的编程中,ASP.NET程序员使用多线程编程的不是很多。其实这种感觉是错误的,我们无时无刻不在享受多线程的优势。首先,Web服务器环境就是一个多线程环境,每一个请求都是独立的线程。如果没有多线程,则很难想象只能同步处理一个请求的Web服务器有什么用。同样道理,数据库也是一个多线程环境。对于 Windows应用程序的程序员来说,恐怕很难不接触多线程,最简单的场景就是新开启线程去完成一些耗时的操作,这样就可以避免UI停止响应,操作结束后再把操作结果应用在主线程的控件上。虽然这样的应用是多线程,甚至很多程序员习惯于什么操作都新开启一个线程去实现。笔者觉得这样的多线程应用的思维还停留在单核时代,在多核时代确实可以让任务实际地并行执行而不是看上去并行执行。

进程和线程的基本概念不用多说,自然我们能理解一个进程至少包含一个线程。通过在一个进程中开启多个线程,就可以让一个程序在同一时间看上去能做多件事情,如可以在接受用户响应的,同时进行一些计算。在以前处理器往往只有一个核心,也就是说在同一时间处理器只能做一件事情。那么怎么实现多个线程同时执行呢?其实这个“同时”只是表面上看上去的“同时”,实质上多个线程依次占用处理器的若干时间片,大家轮流使用其资源。由于这个时间片非常短,所以在一个长的时间内看起来似乎是几个线程同时得到了执行。

举一个生动的例子,经常看到有一些画家能同时在一个画布上画两个不同的图像,如一只手画物,另一只手画房子,最后一起完成这幅画。但仔细观察即会发现,他是两只手分别拿了一只画笔,在这里画一笔,在那里画一笔,在同一时刻其实只有一只笔在画。这个画家应该也像普通人一样是“单核”的,只是线程切换比较快罢了。我们经常在打电话的时候和网友进行聊天,在同一时间做两件事情,但是这样很费脑子,在打字前要回忆一下刚才聊天的内容,然后输入聊天的文字;然后再去回想一下刚才电话那边说了什么,在电话中回复他一句,这种回忆的工作其实就是准备线程的上下文,交给大脑去处理。虽然同一时间是做了两件事情,但是这个上下文的准备工作也浪费了点时间。如果在打电话、网络聊天的同时在去做第三件事情,如看电影等,估计就不行了。所以,线程也不能开启太多,特别对于人脑来说。但是对于电脑处理器来说就不一样了,你只要准备好数据和指令它执行就是了,至于是几件事情它并不关心,每时每刻地执行指令也完全没问题,当然也可以让它闲着。

在并行循环过程中,偶尔也会需要中断循环或跳出循环。例如,下面的代码演示了跳出循环的两种方法:Stop和Break,其中LoopState是循环状态的参数。

      /// <summary>
      /// 中断Stop
      /// </summary>
      private void Demo5()
      {
        List<int> data = Program.Data;
        Parallel.For(0, data.Count, (i, LoopState) =>
        {
          if (data[i] > 5)
            LoopState.Stop();
          Thread.Sleep(500);
          Console.WriteLine(data[i]);
        });
        Console.WriteLine("Stop执行结束。");
      }
      /// <summary>
      /// 中断Break
      /// </summary>
      private void Demo6()
      {
        List<int> data = Program.Data;
        Parallel.ForEach(data, (i, LoopState) =>
        {
          if (i > 5)
            LoopState.Break();
          Thread.Sleep(500);
          Console.WriteLine(i);
        });
        Console.WriteLine("Break执行结束。");
      }

执行效果如图10-3所示。

image

图10-3 执行效果

由此可见,使用Stop会立即停止循环,使用Break会执行完毕所有符合条件的项再停止循环。

在ASP.NET应用中,遍历一个数组内的资源的场景比较常见。为了遍历资源,通常会使用如下的代码:

      private void Demo7()
      {
        List<int> data = new List<int>();
        Parallel.For(0, Program.Data.Count, (i) =>
        {
          if (Program.Data[i] % 2 == 0)
            data.Add(Program.Data[i]);
        });
        Console.WriteLine("执行完成For.");
      }
      private void Demo8()
      {
        List<int> data = new List<int>();
        Parallel.ForEach(Program.Data, (i) =>
        {
          if (Program.Data[i] % 2 == 0)
            data.Add(Program.Data[i]);
        });
        Console.WriteLine("执行完成ForEach.");
      }

对于上述代码,乍看起来应该是没有问题的,但是多次运行后会发现,偶尔也会出现错误,如图10-4所示。

图10-4 错误提示

造成上述错误的原因是List是非线程安全的类,需要在并行循环体内使用System.Collections.Concurrent命名空间下的类型。命名空间System.Collections.Concurrent中主要类的具体说明如表10-2所示。

表10-2 命名空间System.Collections.Concurrent中主要类

说  明

BlockingCollection<T>

为实现IProducerConsumerCollection<T> 的线程安全集合提供阻止和限制功能

ConcurrentBag<T>

表示对象的线程安全的无序集合

ConcurrentDictionary<TKey, TValue>

表示可由多个线程同时访问的键值对的线程安全集合

ConcurrentQueue<T>

表示线程安全的先进先出(FIFO)集合

ConcurrentStack<T>

表示线程安全的后进先出(LIFO)集合

OrderablePartitioner<TSource>

表示将一个可排序数据源拆分成多个分区的特定方式

Partitioner

提供针对数组、列表和可枚举项的常见分区策略

Partitioner<TSource>

表示将一个数据源拆分成多个分区的特定方式

那么上面的代码可以修改为,增加了ConcurrentQueue和ConcurrentStack的最基本操作。

      /// <summary>
      /// 并行循环操作集合类,集合内只取5个对象
      /// </summary>
      private void Demo7()
      {
        ConcurrentQueue<int> data = new ConcurrentQueue<int>();
        Parallel.For(0, Program.Data.Count, (i) =>
        {
          if (Program.Data[i] % 2 == 0)
            data.Enqueue(Program.Data[i]);//将对象加入到队列末尾
        });
        int R;
        while (data.TryDequeue(out R))//返回队列中开始处的对象
        {
          Console.WriteLine(R);
        }
        Console.WriteLine("执行完成For.");
      }
      /// <summary>
      /// 并行循环操作集合类
      /// </summary>
      private void Demo8()
      {
        ConcurrentStack<int> data = new ConcurrentStack<int>();
        Parallel.ForEach(Program.Data, (i) =>
        {
          if (Program.Data[i] % 2 == 0)
            data.Push(Program.Data[i]);//将对象压入栈中
        });
        int R;
        while (data.TryPop(out R))//弹出栈顶对象
        {
          Console.WriteLine(R);
        }
        Console.WriteLine("执行完成ForEach.");
      }

这样就解决了返回一个序列的问题。由此可见,在并行循环内重复操作的对象,必须是Thread-Safe(线程安全)的。集合类的线程安全对象全部在System.Collections.Concurrent命名空间下。

搜索引擎优化(SEO)对任何面向公众的网站来说都是非常重要的,现在网站很大比例的流量来自搜索引擎。ASP.NET 4.5包含很多新的运行时特性,可以帮助用户进一步优化网站。其中一些新特性包含。

  • 新的Page.MetaKeywords和Page.MetaDescription属性。
  • 针对ASP.NET Web Forms的新URL导向支持。
  • 新的Response.RedirectPermanent( )方法。

在接下来的内容中,将简单介绍利用这些特性来进一步提高搜索引擎相关性的知识。

(1)Page.MetaKeywords和Page.MetaDescription属性

改进网页搜索相关性的一个简单建议是,确定总是在HTML中的<head>部分输出相关的“keywords”(关键词)和“description”(描述)<meta>标识。例如:

6Q8QH(7SYB{YB)PBFG4DM4Q

在ASP.NET 4.5 Web Forms中,一个很好的改进是在Page类中增加了两个新属性:MetaKeywords和MetaDescription,它们使得在后台代码类中用编程的手法设置这些值更容易,也更干净。

ASP.NET 4.5的<head>服务器控件现在会检索这些值,然后在输出网页的<head>部分时使用它们。这个行为在使用母版页的场景中尤其有用,<head>是在.master文件中,与含有特定页面内容的.aspx文件是分开的。此时就可以在.aspx页面中设置新的MetaKeywords和MetaDescription属性,它们的值会自动地由母版页中的<head>控件来显示。

下面的代码演示了如何在Page_Load( )事件处理函数中,使用编程手法设置MetaKeywords和MetaDescription属性的过程。

FOYRPSY}E)@@IU1MOD7}E@6

除了在后台代码中使用编程手法设置MetaKeywords和MetaDescription属性外,还可以在.aspx网页顶部的@Page指令中使用声明的方式来设置,下面的代码就演示了这一设置过程。

]W`KBR9)M6P](808C7Y_77N

这就像我们能预期的那样,如果使用编程手法设置这些属性值,则会替代在<head>部分或@Page指令中声明设置的任何值。

(2)ASP.NET Web Forms中的URL导向

URL导向是最先在ASP.NET 3.5 SP1中引进的一个功能,已为ASP.NET MVC应用所用,用于呈现干净的、SEO友好的“Web 2.0”URL。URL导向让配置一个应用来接受并不映射到物理文件的请求URL,我们可以使用导向来定义对用户来说语义上更具含义的URL,这些URL有助于搜索引擎优化(SEO)。

例如,一个显示产品分类的传统网页的URL也许看上去会是这样的:

http://www.mysite.com/products.aspx?category=software

通过使用ASP.NET 4.5中的URL导向引擎现在可以配置应用来接受下面这样的URL来显示同样的信息:

http://www.mysite.com/products/software

在ASP.NET 4.5中,像上面这样的URL现在可以映射到ASP.NET MVC控制器类,也可以映射到基于ASP.NET Web Forms的网页。甚至可以有一个应用,同时含有 Web Forms 和 MVC控制器,使用单一一套导向规则在它们之间映射URL。

(3)Response.RedirectPermanent( )方法

在ASP.NET应用中,开发人员经常使用Response.Redirect( )方法,用编程的手法将对老的URL的请求转到新的URL上。但许多开发人员没有意识到的是,Response.Redirect()方法发送的是一个HTTP 302 Found(临时转向)回复,会在用户尝试访问老的URL时,导致多余的HTTP往返。搜索引擎一般不会跟随多个重新转向跳转,这意味着使用一个临时转向会负面影响你的网页排名。

ASP.NET 4.5引进了一个新的Response.RedirectPermanent(string url)辅助方法,可以用来做一个HTTP 301(永久性重定向)重新定向。这会导致能识别永久性重新定向的搜索引擎,和其他用户代理保存和使用与内容相关联的新URL。这会使你的内容编入索引,你的搜索引擎页面排名得到提高。

下面的代码是使用新的Response.RedirectPermanent()方法重新定向到特定URL的一个例子。

B1HR3)NS2X@37K8Y`5P5T%J

ASP.NET 4.5还引进了新的Response.RedirectToRoute(string routeName)和Response. RedirectToRoute Permanent(string routeName)辅助方法,可以用来通过URL导向引擎做临时或永久性的重新定向。下面的代码演示了发出临时和永久性的重新定向到注册在URL导向系统中的具体路径的(该路径接受一个category参数)方法。

X2~84Z{%]){NM4S%VD$Z7J8

可以同时针对基于ASP.NET Web Forms以及基于ASP.NET MVC的URL使用上面的路径和方法。由此可见,ASP.NET 4.5包含了大量的特性改进来方便建造极致SEO的面向公众的网站。


相关教程

共有条评论 网友评论

验证码: 看不清楚?