[转载]Sql技巧之快速得到表的记录总数

mikel阅读(1251)

[转载]Sql技巧之快速得到表的记录总数 – EricHu’s Tech Space – 博客园.

判断某一个表的记录总数,对于一个开发者来说是最再常见不过的事,我想大家都常用的作法就是:

select count(*) from 表名;

这种做法没做,我这儿主要说的是效率问题。当一个数据表的记录数不是太多时, 这样得到记录总数的效率不是问题。但试想,如果一个表的记录总数超过几百万或者几千万,要再用上面的SQL语句得到表的记录总数,速度会慢得让人难以忍 受。有人会说了,可以一表上建立聚簇集索引呀,不错,若在表的某个字段上建立聚簇索引,第一次执行该语句的时间和没有索引的时间差不多,之后执行上述语 句,速度很快。但如果要经常做增删改操作,建立聚簇索引不是一个明智的做法,将会极大的影响增删改的速度。得到一个数据表的记录总数经常用在以下几个方 面:

一、做数据分页时要得到总记录数。

二、判断数据表的记录数是否过大,是否需要备份数据。

三、用户要求等等。

说了这么多,那么到底如何快速得到一个数据表的记录总数呢?答案是:利用SQLServer数据库的系统视图sys.sysindexes

在MS SQL数据库中,每个数据表都在sys.sysindexes系统表中拥有至少一条记录,记录中的rows 或rowcnt字段会定时记录表的记录总数。注意是定时,这说明了用这个方法得到的总记录数不是一个精确值,原因是MsSQL并不是实时更新该字段的值,而是定时更新,但从实践来看该值和精确值误差不大,如果你希望快速粗略估算表的记录总数,建议你采用该方法。

SQLSEVER帮助文件对sys.sysindexes系统视图的说明为:当前数据库中的每个索引和表在表中各对应一行。说了这么多,直接动手操作便一目了然。

打开SQLServer,执行如下语句:

1 useAdventureWorks 2  select id,object_name(id) as tableName,indid,rows,rowcnt 3  from sys.sysindexes where indid in(0,1)

得到:

© 2010 EricHu

原创作品,转贴请注明作者和出处,留此信息。

[转载]Jumony入门(一)从这里开始

mikel阅读(1127)

[转载]Jumony入门(一)从这里开始 – Ivony… – 博客园.

首先介绍一下Jumony是什么,Jumony是一个.NET的开源项目,项目主页位于:http://jumony.codeplex.com/,采用LGPL协议发布。

Jumony 试图提供在传统Web开发模型中许多难以解决问题的解决方案。一言蔽之,Jumony的一切基础建立在服务器端的HTML DOM之上。在服务器端将HTML(文件或动态网页技术的输出)按照客户端浏览器的处理方式解析为HTML DOM。操纵和处理HTML DOM,就像我们在客户端用JavaScript干的那些事情一样,不同的是,Jumony可以使你依托强大的.NET Framework,来解决以前用脚本和服务器端技术都难以解决的事情。

下载部署

Jumony现在最稳定的版本是Milestone 1,其下载地址在:http://jumony.codeplex.com/releases/view/51380,对于第一次接触Jumony的朋友来说,建议先下载编译好的DLL,即Binary选项:

image

点击Binary链接后,会出现Jumony的许可协议(也就是LGPL),点击image,开始下载。下载后是一个ZIP文件包,打开后可以看到里面有一个目录Binary,将其随便展开到一个文件夹,例如C:\Jumony。然后清点一下DLL的数量,正常情况下应该包含如下DLL:

  • Ivony.Core.dll,包含基础接口,和一些提高编程体验基础扩展方法
  • Ivony.Web.Html.dll,Jumony的核心DLL,定义了抽象HTML DOM模型。并提供大量扩展方法来操纵HTML DOM
  • Ivony.Web.Html.Binding.dll,提供数据绑定支持
  • Ivony.Web.Html.Parser.dll,即Jumony Parser,一个优秀的Html Parser,可以分析HTML文本并创建HTML DOM。
  • HtmlAgilityPack.dll,HtmlAgilityPack 是另一个开源项目,与Jumony Parser一样,是另一个可以分析HTML文本并创建DOM的工具,理论上Jumony可以使用任何HTML分析器来分析HTML并为自己所用,只要有 合适的Adapter。HtmlAgilityPack的项目主页位于:http://htmlagilitypack.codeplex.com/
    值 得注意的是,当你下载Jumony的源代码包或是直接查看Jumony的源代码时,将不会有HtmlAgilityPack的任何源代码,可以去 HtmlAgilityPack的主页下载。HtmlAgilityPack的授权许可协议与Jumony是不同的,这一点要特别注意。
  • HtmlAgilityPack.Adapter.dll,HtmlAgilityPack 的适配器,使得HtmlAgilityPack可以当作Jumony的一个分析器来使用。事实上在M1版本中,Jumony Parser甚至不如HtmlAgilityPack成熟。

除了DLL文件外,pdb文件是用于调试的,而xml文件则是智能提示所必须的,建议都不要删除,保留。

然 后我们需要新建一个网站来玩一下,在这之前,首先要确保你的VS至少是2008或以上,Jumony的最低.NET Framework版本要求是3.5。还在2.0的朋友,就只能说一声抱歉了,因为Jumony的选择器和导航扩展方法乃至于绑定支持,都是极度依赖于 LINQ技术的。几乎不可能在.NET Framework 2.0之下提供简单的实现。

那么我们先新建一个网站(Web项目也行,这里用网站作为示范):

image

这里我把网站建立在了P:\WebSite\JumonyDemo,然后添加引用,找到刚才存放DLL的文件夹,将六个DLL一股脑全部添加引用:

image

然后我们需要配置web.config文件来添加Jumony的环境支持,在Jumony的下载页面上,有现成的已经配置好的web.config下载:

image

根据ASP.NET的版本,可以选择不同的web.config下载。然后替换系统默认的web.config即可,我这里默认创建的网站便是ASP.NET 4的,所以我下载ASP.NET 4的web.config,其内容是这样的:

image

httpHandlers和httpModules里面的内容便是新增的,如果你需要在现有的一个web.config文件中增加Jumony的环境配置,则只需要下载ASP.NET 4的web.config文件,然后将这两段拷贝整合即可。

然 后就可以开始测试Jumony环境了,首先确认一下Web服务器使用的是VS自带的默认ASP.NET Development Server还是IIS,如果是使用IIS调试,则建议先换为VS自带的默认服务器,因为Jumony需要截获html和htm文件的请求,这已经在 web.config中配置,但如果使用IIS作为服务器,则还需要配置IIS这两个扩展名的映射,这很麻烦,而我们在这里只是先玩一下Jumony,所 以建议先用默认的服务器。

来干点坏事

先随便找一个HTML文件来测试一下Jumony是否已经正常工作,这里我写一个Hello World:
image

将其保存为index.htm:

image

然 后添加这个HTML文件的处理程序,Jumony的处理程序事实上就是一个ashx文件,然后要求文件名除了ashx这个扩展名之外的前段与被处理的文件 的文件名一模一样,这样Jumony的RewriteModule就会自动映射。所以这里我要添加的处理程序的文件名是index.htm.ashx。首 先在添加项的对话框中选择一般处理程序(Generic Handler),然后输入文件名index.htm.ashx:

image

系统会帮我们自动添加一些代码,除了类型声明和using之外的代码都是多余的,直接删掉:

image

系统默认的类型名称是index,但为了避免冲突,Jumony建议类名还是命名为index_htm比较妥当,当然这不是必须的。然后我们要添加许多using,以及修改继承的基类型:

image

JumonyHandler是一个抽象类,有一个Process方法需要我们实现:

image

通过实现这个方法,可以让我们对HTML进行操控,当进入这个方法时,HTML文档(index.htm)已经被分析完毕成为一个IHtmlDocument对象静静的躺在一个叫做Document的属性里,等着我们来操控。

首先我们来了解Find方法,这个方法和JQuery的一样,使用CSS选择器来选择元素,在这里我们把Hello World的body元素找出来:

image

Single是LINQ中的方法,所以我说没有LINQ将寸步难行,因为Find方法的结果是一个元素(IHtmlElement)集合,这里用Single方法取出唯一的元素,因为我们知道body一定是唯一的元素。

然后我们干点什么好呢?要不把Hello World改为Hello Jumony!如何?

image

这就完成了我们的第一件“坏事”,赶紧来看看成果。在解决方案中右键点击index.htm,然后选择在浏览器中查看,不出意外的话,应该会看到这样的效果:

image

哦耶,真的变成了Hello Jumony。

来查看一下源代码:

image

清楚的看到了index.htm文件输出被Jumony引擎精确篡改。

再看看原始的文件(即index.htm这个文件原始的样子)是不是还是原来的样子:

image

确实没有变化,还是Hello World。

Jumony截获了htm的请求,并篡改了其结果,完成。

[转载]Android 使用三种方式获取网页(通过Post,Get进行表单的提交)

mikel阅读(882)

[转载]Android 使用三种方式获取网页(通过Post,Get进行表单的提交) – 彬彬的博客 – 博客园.

在这里把三种获取网页内容的信息进行了综合,在前面已经对通过表单提交上传文件进行了处理,现在把这三种方式进行了综合,放到一块,帮助大家进行一个比较,下面为三种方式 的部分代码:

一共三个函数,都可以直接调用,但是在访问网络的时候,记得要加上访问权限

代码

// 直接获取信息 void DirectInfo() throws IOException { URL url = new URL(SRC); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); InputStreamReader inStreamReader = new InputStreamReader(httpConn .getInputStream()); BufferedReader bufReader = new BufferedReader(inStreamReader); String line = ""; String Date = "OK"; while ((line = bufReader.readLine()) != null) { Date += line + "\n"; } edit1.setText(Date); } // get方式获取信息 void getInfo() throws IOException { // 将上面使用的方法直接修改一下即可。 URL url = new URL(SRC+"/default.aspx?NAME=" + URLEncoder.encode("abc", "utf-8")); HttpURLConnection httpconn = (HttpURLConnection) url.openConnection(); InputStreamReader inputReader = new InputStreamReader(httpconn .getInputStream()); BufferedReader bufReader = new BufferedReader(inputReader); String line = ""; String Date = ""; while ((line = bufReader.readLine()) != null) { Date += line; } edit1.setText(Date); } // Post方式获取信息 void postInfo() throws MalformedURLException, IOException { // Post 方法比Get方法需要设置的参数更多 HttpURLConnection httpconn = (HttpURLConnection) new URL(SRC) .openConnection(); // post 方式,输入输出需要设置为true httpconn.setDoInput(true); httpconn.setDoOutput(true); httpconn.setRequestMethod("POST"); // 设置为Post方式,默认为get方式 httpconn.setUseCaches(false); // 不使用缓存 httpconn.setInstanceFollowRedirects(true); // 重定向 httpconn.setRequestProperty("Content-type", "Application/x-www-form-urlencoded"); // 设置连接 的Content-type类型为: // application/x-www-form-urlencoded httpconn.connect(); //连接 DataOutputStream out = new DataOutputStream(httpconn.getOutputStream()); //声明数据写入流 String content = "NAME="+URLEncoder.encode("fly_binbin", "gb2312"); out.writeBytes(content); out.flush(); out.close(); BufferedReader reader = new BufferedReader(new InputStreamReader(httpconn.getInputStream())); String line = ""; String resultDate = ""; while((line=reader.readLine())!=null) { resultDate += line; } edit1.setText(resultDate); }

网址的话,可以自己做一个测试服务器。我这个测试服务器是我自己写的,进行测试用的,用ASP.NET写的,用其它的方法写的结果是一样的。包括使用Web服务结果也是一样的!

[转载]ASP.NET MVC中的扩展点(二)路由(Route)上的扩展

mikel阅读(1005)

[转载]MVC中的扩展点(二)路由上的扩展 – xfrog – 博客园.

一、RouteBase

前面我们知道,UrlRoutingModule通过遍历RouteTable.Routes中的路由对象来获取匹配的RouteData,从而将请求转 发到相应的IHttpHandler处理程序。RouteTable.Routes是一个RouteBase对象集合,可向集合中添加任何 RouteBase的子类。所以,我们可以通过创建一个RouteBase的子类,然后将其添加到RouteTable.Routes集合中,以此实现自 定义路由规则。

RouteBase是一个抽象类,包含两个抽象方法:GetRouteData用于检查请求上下文是否符合路由规则,如果符合返回一个RouteData 对象,若不符合则返回null,UrlRoutingModule在在遍历Routes集合时,将调用此方法,如果方法返回非空,则终止遍历,并将返回的 RouteData保存到请求上下文(RequestContext)中。GetVirtualPath方法用于检查指定的路由信息是否符合本路由规则, 如果符合返回一个VirtualPathData对象,通过该对象可以获取响应的Url,如果不符合则返回null,通常我们通过MVC中的 Html.RouteLink方法来生成Url时,此方法会遍历RoueTable.Routes中的路由对象,依次调用GetVirtualPath方 法,直到方法返回非空。

下面我们将创建一个MyRoute类,该类将阻止IE浏览器方法网站

1、首先,我们创建一个MVC2空应用程序项目,然后创建一个名为Home的控制器,在控制器中创建两个Action:Index表示网站首页,Limit表示一个显示限制信息的页面,如果浏览器为IE则会直接显示此页面类容。

2、创建Index和Limit活动所对应的视图。

显示行号 复制代码 Index.aspx
  1.     <div>
  2.     <h1>欢迎-!</h1>
  3.     </div>

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }

显示行号 复制代码 Limit.aspx
  1.     <div>
  2.     不允许IE浏览器访问
  3.      <%= Html.RouteLink("MyRoute", new {applay="IE" }) %>
  4.      <%= Html.RouteLink("Route", new { controller = "Home", action = "Index" })%>
  5.     </div>

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }3、创建一个MyRoute类,让其继承自RouteBase,重写GetRouteData和GetVirtualPath方法:

显示行号 复制代码 MyRoute.cs
  1. public class MyRoute : RouteBase
    
  2. {
    
  3.     public override RouteData GetRouteData(HttpContextBase httpContext)
    
  4.     {
    
  5.         if (httpContext.Request.UserAgent.IndexOf("MSIE")>=0 )
    
  6.         {
    
  7.             RouteData rd = new RouteData(this, new MvcRouteHandler());
    
  8.             rd.Values.Add("controller", "Home");
    
  9.             rd.Values.Add("action", "Limit");
    
  10.             return rd;
    
  11.         }
    
  12.         return null;
    
  13.     }
    
  14.     public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    
  15.     {
    
  16.         if (values.ContainsKey("applay") && values["applay"] == "IE")
    
  17.         {
    
  18.             return new VirtualPathData(this, "IE/Index");
    
  19.         }
    
  20.         return null;
    
  21.     }
    
  22. }
    
  23. 
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }4、打开Global.asax.cs文件,找到RegisterRoutes方法,将我们的 MyRoute注册到RouteTable.Routes集合中,注意添Route的顺序很重要,UrlRoutingModule在遍历时是按照添加顺 序进行的,所以未保证MyRoute规则有效,必须将其放到第一个位置。注意MapRoute方法是MVC框架对RouteCollection的扩展, 用于添加一个Route对象到集合中,本质上内部也是调用的Add方法。

显示行号 复制代码 MvcApplication
  1. public static void RegisterRoutes(RouteCollection routes)
    
  2. {
    
  3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
  4.     routes.Add("myRoute",new MyRoute());
    
  5.     routes.MapRoute(
    
  6.         "Default", // Route name
    
  7.         "{controller}/{action}/{id}", // URL with parameters
    
  8.         new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    
  9.     );
    
  10. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }

启动调试,如果是IE浏览器,则会显示“不允许IE浏览器访问”,另外,请注意看MyRoute与Route连接的地址,显然MyRoute的地址是通过MyRoute类产生的,而Route地址是通过Route默认路由对象产生的。

二、IRouteHandler

UrlRoutingModule在获取到合适的RouteData后,将通过其RouteHandler属性来获取实际的IHttpHandler对 象,通过IHttpHandler来处理请求。在MVC中,已经实现了一个RouteHandler,即MvcRouteHandler,在上例中我们的 GetRouteData方法使用的即是MvcRouteHandler。

IRouteHandler接口只有一个方法:GetHttpHandler它返回一个IHttpHandler对象。也就是说最终页面的生成是在 IHttpHandler对象中实现的。对应于MVC,MvcRouteHandler的GetHttpHandler方法返回一个MvcHandler 对象,MvcHandler对象负责调用合适的Controller与Action方法。

下面我们沿用上例,实现一个IERouteHandler,通过这个Handler来处理来自IE浏览器的请求。

1、添加一个IERouteHandler类,继承自IRouteHandler,实现其GetHttpHandler方法,返回一个IEHandler对象。

显示行号 复制代码 IERouteHandler
  1. public class IERouteHandler : IRouteHandler
    
  2. {
    
  3.     #region IRouteHandler Members
    
  4.     public IHttpHandler GetHttpHandler(RequestContext requestContext)
    
  5.     {
    
  6.         return new IEHandler();
    
  7.     }
    
  8.     #endregion
    
  9. 
    
  10. 
    
  11.     private class IEHandler : IHttpHandler
    
  12.     {
    
  13.         #region IHttpHandler Members
    
  14.         public bool IsReusable
    
  15.         {
    
  16.             get { return true; }
    
  17.         }
    
  18.         public void ProcessRequest(HttpContext context)
    
  19.         {
    
  20.             context.Response.Write("不允许IE浏览器访问");
    
  21.         }
    
  22.         #endregion
    
  23.     }
    
  24. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }2、修改MyRoute的GetRouteData方法,将之前的MvcRouteHandler修改为IERouteHandler

显示行号 复制代码 MyRoute
  1. public override RouteData GetRouteData(HttpContextBase httpContext)
    
  2. {
    
  3.     if (httpContext.Request.UserAgent.IndexOf("MSIE")>=0 )
    
  4.     {
    
  5.         //RouteData rd = new RouteData(this, new MvcRouteHandler());
    
  6.         //rd.Values.Add("controller", "Home");
    
  7.         //rd.Values.Add("action", "Limit");
    
  8.         RouteData rd = new RouteData(this, new IERouteHandler());
    
  9.         return rd;
    
  10.     }
    
  11.     return null;
    
  12. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }

三、IRouteConstraint

IRouteConstraint接口由Route类的Constraints属性使用,用于判断当前的Url是否符合路由的约束条件。Route已经实现了一个HttpMethodConstraint用于限制请求方法,例如:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
    new { method = new HttpMethodConstraint("POST") }
);

.codearea { color: black; background-color: white; line-height: 18px; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,”BitStream Vera Sans Mono”,courier,monospace,serif; }.codearea pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap pre { white-space: pre-wrap; word-wrap: break-word; }.codearea pre.alt { background-color: rgb(247, 247, 255) ! important; }.codearea .lnum { color: rgb(79, 129, 189); line-height: 18px; }表明此项路由规则必须是POST请求才有效,即就算Url为Home/Index形式,符合Url规则,但是如果请求是通过的GET方法,那此项规则也不 满足,明显,Route的GetRouteData方法中会检查所有的约束条件,如果某项约束条件不满足仍然会返回null。

IRouteConstraint接口有一个Match方法,如果请求上下文符合约束返回true否则返回false。

沿用上例,现在我们通过IRouteConstraint来限制IE浏览器的访问:

1、新建类IERouteConstraint,实现其Match方法:

显示行号 复制代码 IERouteConstraint
  1. public class IERouteConstraint : IRouteConstraint
    
  2. {
    
  3.     #region IRouteConstraint Members
    
  4.     public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    
  5.     {
    
  6.         return !(httpContext.Request.UserAgent.Contains("MSIE"));
    
  7.     }
    
  8.     #endregion
    
  9. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }2、修改Global.asax.cs的RegisterRoutes方法,屏蔽掉之前加入的MyRoute规则,然后修改默认的MapRoute:

显示行号 复制代码 MvcApplication
  1. public static void RegisterRoutes(RouteCollection routes)
    
  2. {
    
  3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
  4.     //  routes.Add("myRoute",new MyRoute());
    
  5.     routes.MapRoute(
    
  6.         "Default", // Route name
    
  7.         "{controller}/{action}/{id}", // URL with parameters
    
  8.         new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
    
  9.         new { ie = new IERouteConstraint() }
    
  10.     );
    
  11. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }

启动调试,如果是IE浏览器,将显示一个无法找到资源的404错误。

源代码下载

[转载]Android 文件的下载

mikel阅读(914)

[转载]Android 文件的下载 – 彬彬的博客 – 博客园.

上一篇内容,实现了文件的上传,文件的上传其实就是自己组合成Post表单的形式进行Http的Post发送,这一篇要实现的是文件的下载,其实下载文件与打开网页是一样的,打开网页是将内容显示出来,保存文件就是保存到文件中即可。

实现的代码基本如下:

代码

public void downFile(String url, String path, String fileName) throws IOException { if (fileName == null || fileName == "") this.FileName = url.substring(url.lastIndexOf("/") + 1); else this.FileName = fileName; // 取得文件名,如果输入新文件名,则使用新文件名 URL Url = new URL(url); URLConnection conn = Url.openConnection(); conn.connect(); InputStream is = conn.getInputStream(); this.fileSize = conn.getContentLength();// 根据响应获取文件大小 if (this.fileSize <= 0) { // 获取内容长度为0 throw new RuntimeException("无法获知文件大小 "); } if (is == null) { // 没有下载流 sendMsg(Down_ERROR); throw new RuntimeException("无法获取文件"); } FileOutputStream FOS = new FileOutputStream(path + this.FileName); // 创建写入文件内存流,通过此流向目标写文件 byte buf[] = new byte[1024]; downLoadFilePosition = 0; int numread; while ((numread = is.read(buf)) != -1) { FOS.write(buf, 0, numread); downLoadFilePosition += numread } try { is.close(); } catch (Exception ex) { ; } }

通过此代码就可以实现将内容保存到SD卡等设备上,当然要使用网络,必须得有网络的访问权限。这个需要自己添加,在这里不再添加!

上面的代码没有实现进度条功能,如果要实现进度条功能,我现在考虑到的就是使用消息进行发送提示,首先实现一个消息。

代码

private Handler downloadHandler = new Handler() { // 用于接收消息,处理进度条 @Override public void handleMessage(Message msg) { // 接收到的消息,并且对接收到的消息进行处理 if (!Thread.currentThread().isInterrupted()) { switch (msg.what) { case DOWN_START: pb.setMax(fileSize); //设置开始长度 case DOWN_POSITION: pb.setProgress(downLoadFilePosition); // 设置进度 break; case DOWN_COMPLETE: Toast.makeText(DownLoadFileTest.this, "下载完成!", 1).show(); // 完成提示 break; case Down_ERROR: String error = msg.getData().getString("下载出错!"); Toast.makeText(DownLoadFileTest.this, error, 1).show(); break; } } super.handleMessage(msg); } };

这样,在下载的时候只要发送相应的消息,即可有相应的提示!不再细写,希望对你的思路有帮助!在这里仅仅提供一个思路,如果你有更好的想法,欢迎交流!

[转载]Android 文件的上传

mikel阅读(1139)

[转载]Android 文件的上传 – 彬彬的博客 – 博客园.

因为工作需要,暂时没有对GPS(2)完成,今天开始完成了,一个文件上传的内容的实现,Android要实现文件上传,可以利用Socket上 传,也可以模拟Web进行上传,但是如果是使用第一种方式上传,严格的话就得使用TCP,这样容易生成系统死掉,或者是长时间等待,如果是UDP来传,就 容易造成数据丢失,因此在这里选择了Web进行上传,使用Web进行上传是模拟的Http Post上传数据,当然,Post上传数据的类,在网上找了一找,方式虽然很多,但是没有一个感觉是我所使用的,所以参照原理之类的,进行了一下修改,算 是做了一个参考。并且利用这个类完成了文件和表彰的上传服务。

具体代码如下:

文件与表单上传类:

代码

package com.UpLoadFileTest; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; public class PostFile { //上传代码,第一个参数,为要使用的URL,第二个参数,为表单内容,第三个参数为要上传的文件,可以上传多个文件,这根据需要页定 public static String post(String actionUrl, Map<String, String> params, Map<String, File> files) throws IOException { String BOUNDARY = java.util.UUID.randomUUID().toString(); String PREFIX = "--", LINEND = "\r\n"; String MULTIPART_FROM_DATA = "multipart/form-data"; String CHARSET = "UTF-8"; URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(5 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); //Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); // 首先组拼文本类型的参数 StringBuilder sb = new StringBuilder(); for (Map.Entry<String, String> entry : params.entrySet()) { sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINEND); sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND); sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND); sb.append("Content-Transfer-Encoding: 8bit" + LINEND); sb.append(LINEND); sb.append(entry.getValue()); sb.append(LINEND); } DataOutputStream outStream = new DataOutputStream(conn .getOutputStream()); outStream.write(sb.toString().getBytes()); // 发送文件数据 if (files != null) for (Map.Entry<String, File> file : files.entrySet()) { StringBuilder sb1 = new StringBuilder(); sb1.append(PREFIX); sb1.append(BOUNDARY); sb1.append(LINEND); sb1 .append("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getKey() + "\"" + LINEND); sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINEND); sb1.append(LINEND); outStream.write(sb1.toString().getBytes()); InputStream is = new FileInputStream(file.getValue()); byte[] buffer = new byte[1024]; int len = 0; while ((len = is.read(buffer)) != -1) { outStream.write(buffer, 0, len); } is.close(); outStream.write(LINEND.getBytes()); } // 请求结束标志 byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); outStream.write(end_data); outStream.flush(); // 得到响应码 int res = conn.getResponseCode(); InputStream in = conn.getInputStream(); InputStreamReader isReader = new InputStreamReader(in); BufferedReader bufReader = new BufferedReader(isReader); String line = null; String data = "OK"; while((line = bufReader.readLine())==null) data += line; if (res == 200) { int ch; StringBuilder sb2 = new StringBuilder(); while ((ch = in.read()) != -1) { sb2.append((char) ch); } } outStream.close(); conn.disconnect(); return in.toString(); } }

以上如果要写入(上传)数据,这里使用的是out.write亦可使用out.wrtebyte(content)这样子也可以,省得在这里转换了,交给系统进行转换

这个可以根据个人的需要,加上等待条等等,如果要加上等待条的话,需要使用发送消息的方式进行,这个是我所想到的,其它的方式没有考虑好呢,有兴趣的人可以自己加上去!我在这里不再给增加了,增加的话,将在下载中添加一个下载的进度提示条。

实现内容如下:

代码

Button btn1; EditText view1; EditText text1; String SDPath = "/sdcard/"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); view1 = (EditText) findViewById(R.id.view1); text1 = (EditText) findViewById(R.id.edit1); btn1 = (Button) findViewById(R.id.btn1); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub getFile(); try { String name=URLEncoder.encode(text1.getText().toString(),"utf-8"); Map<String, String> params = new HashMap<String, String>(); params.put("NAME", name); Map<String, File> files = new HashMap<String, File>(); files.put(getFile(), new File("/sdcard/"+getFile())); view1.setText(PostFile.post("http://wdsl.recordinfo.tk/default.aspx", params, files)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } String getFile() { File file = new File(SDPath); File[] files = file.listFiles(new fileFilter()); String filename = ""; for (File file1 : files) { filename = file1.getName(); } Toast.makeText(this, filename, Toast.LENGTH_LONG).show(); return filename; } class fileFilter implements FilenameFilter { @Override public boolean accept(File dir, String filename) { // TODO Auto-generated method stub return filename.endsWith(".gif"); } }

这些只是类里面的内容,并且我只取了SD卡上的一张照片,因此我就在卡上放了一张照片,所以没有进行列表处理,有兴趣的话,可以自己添加上去,因为我主要是实现这一功能,对这一功能进行练习!

要使用SD卡和网络,相应的权限需要加上,因为在前面已经有了,这里将不写赘述。

[转载]Lucene.Net 2.4.0无障碍学习和使用:索引篇

mikel阅读(835)

[转载]Lucene.Net 2.4.0无障碍学习和使用:索引篇 – 努力,天赋,笑容,自信 – 博客园.

项目中可能需要再次用到Lucene.Net,利用空闲时间写了个demo,主要涉及到索引的创建、删除、更新和一个简单查询。在本文示例中,Lucene.Net的版本是2.4.0,某些类和方法与最新版本或者较旧的版本有较多不同,希望您阅读顺利。

一、简单认识索引

Lucene.Net的应用相对比较简单。一段时间以来,我最多只是在项目中写点代码,利用一下它的类库而已,对很多名词术语不是很清晰,甚至理解 可能还有偏差。从我过去的博客你也可以看出,语言表达一直不是个人所长,就算”表达“了也有大面积抄书的嫌疑,所以很多概念性的介绍能省则省(除非特别有 别要说明),希望有心的初学者注意,理清概念和辨别技术名词非常重要,请参考相关文档。

Lucene的索引由1或多个segment(片段)构成,一个segment由多个document构成,一个document又由1个或多个field构成,一个field又由一个或多个term构成。下面这张图可以说明一切:

lucenenetindex

从图中不难看出,Lucene的索引是一个由点到线,由线到面的组成结构,这一点我们可以通过查看Lucene生成的索引文件看出来。

参考图片来源: http://alone2004.spaces.live.com/blog/cns!C2525069080D7BB!675.entry

二、创建、优化、删除和更新索引实践

备注:在解决方案所在文件夹中,有一个测试用的Resource文件夹,内有4个.txt文件。我在本地测试的时候,就使用了Resource下的四个文本文件。

1、索引保存至文件

(1)、创建索引

先初始化一个IndexModifier对象,然后执行创建索引的核心方法:

01 /// <summary>
02 /// 给txt文件创建索引
03 /// </summary>
04 /// <param name="file"></param>
05 /// <param name="modifier"></param>
06 private void IndexFile(FileInfo file, IndexModifier modifier)
07 {
08 try
09 {
10 Document doc = new Document();//创建文档,给文档添加字段,并把文档添加到索引书写器里
11 SetOutput("正在建立索引,文件名:" + file.FullName);
12
13 doc.Add(new Field("id", id.ToString(), Field.Store.YES, Field.Index.TOKENIZED));//存储且索引
14 id++;
15
16 /* filename begin */
17 doc.Add(new Field("filename", file.FullName, Field.Store.YES, Field.Index.TOKENIZED));//存储且索引
18 //doc.Add(new Field("filename", file.FullName, Field.Store.YES, Field.Index.UN_TOKENIZED));
19 //doc.Add(new Field("filename", file.FullName, Field.Store.NO, Field.Index.TOKENIZED));
20 //doc.Add(new Field("filename", file.FullName, Field.Store.NO, Field.Index.UN_TOKENIZED));
21 /* filename end */
22
23 /* contents begin */
24 //doc.Add(new Field("contents", new StreamReader(file.FullName, System.Text.Encoding.Default)));
25
26 string contents = string.Empty;
27 using (TextReader rdr = new StreamReader(file.FullName, System.Text.Encoding.Default))
28 {
29 contents = rdr.ReadToEnd();//将文件内容提取出来
30 doc.Add(new Field("contents", contents, Field.Store.YES, Field.Index.TOKENIZED));//存储且索引
31 //doc.Add(new Field("contents", contents, Field.Store.NO, Field.Index.TOKENIZED));//不存储索引
32 }
33 /* contents end */
34 modifier.AddDocument(doc);
35 }
36
37 catch (FileNotFoundException fnfe)
38 {
39 }
40 }

最后,IndexModifier对象执行Close方法。

几个注意点:

a、IndexModifier类封装了平时经常使用的IndexWriter和IndexReader,而且不用我们额外考虑多线程;

b、StandardAnalyzer是经常使用的一个Analyzer,目前对中文分词支持的也还不错(大名鼎鼎的盘古分词请参考牛人eaglet的这几篇);

c、IndexModifier的Optimize方法的执行可以优化索引文件,但是比较耗时间,根据我的测试,索引文件越大,优化时间线性增加,所以实际的开发中这个方法我们都会按照一定的策略执行;

c、IndexModifier的Close方法必须执行,否则你所做的一切都是无用功。

(2)、按照id删除一条索引

代码相对而言非常简单,直接利用IndexModifier 的DeleteDocuents方法:

1 Directory directory = FSDirectory.GetDirectory(INDEX_STORE_PATH, false);
2 IndexModifier modifier = new IndexModifier(directory, new StandardAnalyzer(), false);
3
4 Term term = new Term("id", id);
5 modifier.DeleteDocuments(term);//删除
6 modifier.Close();
7 directory.Close();

其中,IndexModifier还有一个方法DeleteDocument,它的参数是整数docNum,通常我们也不知道索引文件的内部docNum是多少,所以非常少用它。

(3)、按照id更新一条索引

贴一下主要方法:

01 bool enableCreate = IsEnableCreated();//是否已经创建索引文件
02 Term term = new Term("id", id);
03 Document doc = new Document();
04 doc = new Document();//创建文档,给文档添加字段,并把文档添加到索引书写器里
05 doc.Add(new Field("id", id, Field.Store.YES, Field.Index.TOKENIZED));//存储且索引
06 doc.Add(new Field("filename", filename, Field.Store.YES, Field.Index.TOKENIZED));
07 doc.Add(new Field("contents", filename, Field.Store.YES, Field.Index.TOKENIZED));
08 LuceneIO.Directory directory = LuceneIO.FSDirectory.GetDirectory(INDEX_STORE_PATH, enableCreate);
09 IndexWriter writer = new IndexWriter(directory, new StandardAnalyzer(),IndexWriter.MaxFieldLength.LIMITED);
10 writer.UpdateDocument(term, doc);
11 writer.Optimize();
12 //writer.Commit();
13 writer.Close();
14 directory.Close();

需要注意,这一次,我们使用了IndexWriter对象的UpdateDocument方法,而IndexModifier没有找到现成的UpdateDocument方法。Optimize通常需要执行一下,否则索引文件中会有两个相同id的索引。

2、索引保存至内存

如果1你已经理解了,2其实可以不用细究。在IndexModifier的构造函数里有一个重载:

1 public IndexModifier(Directory directory, Analyzer analyzer, bool create);

下面的示例代码中第一个参数RAMDirectory就是一个Directory,我们可以把它定义成静态,创建索引的时候就完成了保存至内存的效果:

1 private static RAMDirectory ramDir = null;
2 IndexModifier  modifier = new IndexModifier(ramDir, new StandardAnalyzer(), true);

经测试,增删改查原理同1

3、利用Lucene.Net配合数据库查询

平时开发中,对于数据库中的海量数据,频繁读库可能不能满足效率和速度的需求。我们也可以利用Lucene.Net配合数据库快速查询结果。至于如何对数据库利用Lucene.Net创建索引,增删改查和同1中的介绍是一模一样的。比如本文demo中创建索引的实现,取前1000个人对他们的Id和姓名进行索引。在编码之前,我先往Person表中插入了一些数据:

1 INSERT Person(FirstName,LastName,Weight,Height) VALUES('明','姚',200,223)
2 INSERT Person(FirstName,LastName,Weight,Height) VALUES('建联','易',180,213)
3 INSERT Person(FirstName,LastName,Weight,Height) VALUES('德科','诺维斯基',180,211)
4 INSERT Person(FirstName,LastName,Weight,Height) VALUES('德怀特','霍华德',190,218)
5 INSERT Person(FirstName,LastName,Weight,Height) VALUES('约什','霍华德',178,197)
6 INSERT Person(FirstName,LastName,Weight,Height) VALUES('蒂姆','邓肯',183,211)
7 INSERT Person(FirstName,LastName,Weight,Height) VALUES('凯文','加内特',182,215)
8 INSERT Person(FirstName,LastName,Weight,Height) VALUES('德隆','威廉姆斯',166,197)

接着先取出1000个人:

1 string SQL = "SELECT TOP 1000 Id,FirstName,LastName FROM Person(NOLOCK)";
2 IList<Person> listPersons = EntityConvertor.QueryForList<Person>(SQL, strSQLConn, null);

然后建立索引即可:

01 private void IndexDB(IndexModifier modifier,IList<Person> listModels)
02 {
03 SetOutput(string.Format("正在建立数据库索引,共{0}人",listModels.Count));
04 foreach (Person item in listModels)
05 {
06 Document doc = new Document();//创建文档,给文档添加字段,并把文档添加到索引书写器里
07 doc.Add(new Field("id", item.Id.ToString(), Field.Store.YES, Field.Index.TOKENIZED));//存储且索引
08 doc.Add(new Field("fullname", string.Format("{0} {1}",item.FirstName,item.LastName), Field.Store.YES, Field.Index.TOKENIZED));//存储且索引
09 modifier.AddDocument(doc);
10 }
11 }

同样的道理,最后我们也执行这两个方法(Optimize方法不是一定要做的):

1 modifier.Optimize();//优化索引
2 modifier.Close();//关闭索引读写器

三、搜索

本文示例代码中的搜索都是利用Lucene.Net的IndexSearcher默认的比较直接简单的一个搜索方法 Search(Query query, Filter filter, int n),很多重载方法我也没有使用过:

01 /// <summary>
02 /// 根据索引搜索
03 /// </summary>
04 /// <param name="keyword"></param>
05 /// <returns></returns>
06 private TopDocs Search(string keyword,string field)
07 {
08 TopDocs docs = null;
09 int n = 10;//最多返回多少个结果
10 SetOutput(string.Format("正在检索关键字:{0}", keyword));
11 try
12 {
13 QueryParser parser = new QueryParser(field, new StandardAnalyzer());//针对内容查询
14 Query query = parser.Parse(keyword);//搜索内容 contents  (用QueryParser.Parse方法实例化一个查询)
15 Stopwatch watch = new Stopwatch();
16 watch.Start();
17 docs = searcher.Search(query, (Filter)null, n); //获取搜索结果
18 watch.Stop();
19 StringBuffer sb = "索引完成,共用时:" + watch.Elapsed.Hours + "时 " + watch.Elapsed.Minutes + "分 " + watch.Elapsed.Seconds + "秒 " + watch.Elapsed.Milliseconds + "毫秒";
20 SetOutput(sb);
21 }
22 catch (Exception ex)
23 {
24 SetOutput(ex.Message);
25 docs = null;
26 }
27 return docs;
28 }
29
30 /// <summary>
31 /// 显示搜索结果
32 /// </summary>
33 /// <param name="queryResult"></param>
34 private void ShowFileSearchResult(TopDocs queryResult)
35 {
36 if (queryResult == null || queryResult.totalHits == 0)
37 {
38 SetOutput("Sorry,没有搜索到你要的结果。");
39 return;
40 }
41
42 int counter = 1;
43 foreach (ScoreDoc sd in queryResult.scoreDocs)
44 {
45 try
46 {
47 Document doc = searcher.Doc(sd.doc);
48 string id = doc.Get("id");//获取id
49 string fileName = doc.Get("filename");//获取文件名
50 string contents = doc.Get("contents");//获取文件内容
51 string result = string.Format("这是第{0}个搜索结果,Id为{1},文件名为:{2},文件内容为:{3}{4}", counter, id, fileName, Environment.NewLine, contents);
52 SetOutput(result);
53 }
54 catch (Exception ex)
55 {
56 SetOutput(ex.Message);
57 }
58 counter++;
59 }
60 }

下一篇我会补充介绍一下Lucene.Net常用的搜索、排序和分页,今天偷懒一下。

最后,本文demo中的代码算不上优美,可读性还凑合,希望大家下载之后看看吧,我还在幻想万一对新手能有所帮助,或者引来某个误入的高手指点一二,于人于己那就真是善莫大焉了。

demo下载:LuceneNetApp

参考:

http://www.cnblogs.com/birdshover/category/152283.html

http://lucene.apache.org/lucene.net/

http://lucene.apache.org/lucene.net/docs/

[转载]第一个新浪微博应用

mikel阅读(1192)

[转载]第一个新浪微博应用_不同樊响_新浪博客.
我开发的第一个新浪微博应用“蟹爪消息导入”,已经通过新浪审核 了,就像应用页面所说的一样,是因为自己有这样的需求,所以干起来特别卖劲,从开始操起遗忘了N年的PHP和JS,利用闲暇时间完成这个应用,用了不到一 个星期的时间,最开始通过dome入手到熟悉流程开发花2天时间,后来开发就比较顺了,主要是百度加实现。

作者最开始用的微博是饭否,结果饭否莫名其妙关闭了,接着找到的是和饭否最相似的蟹爪,而且支持饭否的导入。

后来新浪微博开测了,作者也开始使用,觉得不错就一直用新浪微博了,不过作者有收集癖好,希望所有的微薄都能集合在一起,正好新浪微博有开放平台,所以就有了这个应用。

如果你也和作者一样有收集癖,正好和作者使用的微薄一样轨迹,不妨试试也把饭否和蟹爪微薄导入到新浪微博。

想要做一个新浪微博应用,首先要到新浪微博开放平台创建账户,可以参照新手指南操作,这里有一个问题,创建应用时需要填写一个“应用地址”,对于没有主机资源的普通开发者来说,这是一个问题。但是如果你使用PHP开放的话,这里推荐SAE(Sina App Engine)

SAE是Sina App Engine(新浪应用引擎)的缩写,SAE是一个分布式web应用开发运行的服务平台,其不仅仅包含创建、部署web应用的简单交互,更涉及一整套大规 模分布式服务的解决方案。用户通过SAE可以方便的创建web应用、定制web应用、开发web应用、部署web应用、切换线上版本、删除应用,大大节省 了开发者的开发成本和运维成本。

SAE注册需要邀请码,否则只能注册体验用户,体验用户只能试用5天,过期后删除账户和所有代码,当然,你可以在5天内开发完代码,申请转正,或者再重新注册体验用户。

在SAE里创建一个应用,然后在代码管理里新建一个版本,这样就可以开始开发了。

第一个新浪微博应用

SAE使用SDK工具进行代码上传了,其实叫SDK工具有些勉强,明明现在只是个上传工具加强版。

第一个新浪微博应用

PHP开发先可以参考这两篇文章:《用于微博开放平台OAuth的lib SaeT上线了》《SaeT lib升级,原SaeT Class改名为SaeTOAuth,新增SaeTClient》。然后下载dome上传测试一下。

Demo使用教程
1. 下载,然后解压,修改config.php中的key
2. 打开index.php,将13行最后一个url改成你网站对应的callback.php的url
3. 上传到PHP空间即可

注意index.php页面回调页面的地址必须正确,特别是注意版本号。否则就会报如下错误:

 Error_code: 400; Error: 40022:Error: source paramter(appkey) is missing? 

如果你是通过http://xiezhua.sinaapp.com访问时,回调页面就应该是http: //xiezhua.sinaapp.com/callback.php;如果你是带版本号http://1.xiezhua.sinaapp.com访问时,回调页面就应该是http://1.xiezhua.sinaapp.com/callback.php。

当初出现这个问题调试了很久,到群里问大多都说是App Key和App Secret不正确,因为从错误描述只能这么猜测。我估计是跨域丢失引起的问题。

Dome调通后,后面实现就比较容易了。

主要碰到下面几个问题:
1.SAE上传文件比较麻烦,我用textarea替换了。
2.新浪微博API不允许频繁调用,估计是为了防止垃圾内容。后来我用了JS的timeout控制每30秒通过AJAX发送一次。
3.IE和FF Ajax兼容时出现乱码问题,通过encodeURI(url)进行控制。

下面是代码实现。

index.php

1 <?php

2 
 3 session_start();
 4 if( isset($_SESSION['last_key']) ) header("Location: weibolist.php");
 5 include_once( 'config.php' );
 6 include_once( 'saet.ex.class.php' );
 7 
 8 
 9 
10 $o = new SaeTOAuth( WB_AKEY , WB_SKEY  );
11 
12 $keys = $o->getRequestToken();
13 $aurl = $o->getAuthorizeURL( $keys['oauth_token'] ,false , 'http://' . $_SERVER['HTTP_APPNAME'] . '.sinaapp.com/callback.php');
14 
15 $_SESSION['keys'] = $keys;
16 
17  header("Location: ".$aurl);
18 ?>
19 <a href="<?=$aurl?>">Use Oauth to login</a> 

callback.php

1 <?php

2 
 3 session_start();
 4 include_once( 'config.php' );
 5 include_once( 'saet.ex.class.php' );
 6 
 7 
 8 $o = new SaeTOAuth( WB_AKEY , WB_SKEY , $_SESSION['keys']['oauth_token'] , $_SESSION['keys']['oauth_token_secret']  );
 9 
10 $last_key = $o->getAccessToken(  $_REQUEST['oauth_verifier'] ) ;
11 
12 
13 $_SESSION['last_key'] = $last_key;
14 
15 header('Location: xiezhua.php');
16 ?> 

xiezhua.php

 1 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

2 <style type="text/css">
 3 * {
 4  font-size : 12px;
 5  color: #4682B4;
 6 }
 7 body{background-color:#ddf3f7;}
 8 table{
 9  background-color:#FFF;
10 }
11 .pic
12 {
13 background-color: #71cae0;
14 display: block;
15 padding-top: 4px;
16 padding-right: 4px;
17 padding-bottom: 4px;
18 padding-left: 4px;
19 }
20 .button {
21  width: 400px;
22 }
23 .ok {
24  color: green;
25 }
26 .err {
27  color: red;
28 }
29 </style>
30 <table width="800" border="0" align="center" cellpadding="5" cellspacing="0">
31   <tr>
32     <td colspan="2"><img src="xiezhuaimp00.gif"alt="蟹爪消息导入" /><img src="xiezhuaimp01.gif" alt="蟹爪消息导入" /></td>
33   </tr>
34   <tr>
35     <td width="400" valign="top" hegth="600">
36 
37   <textarea name="xz" id="xz" cols="65" rows="20" ></textarea><br><br>
38 导入的格式是第一行是蟹爪的消息,第二份是消息发布时间,依此类推。??<br><br>
39 好吧,其实不一定是蟹爪的消息,只要符合格式都可以导入。这个你懂的。<br><br>
40   <input class="button" name="sb" text="" value="OK,我明白了,开始导入" type="button" onclick="update()">
41 
42   <p>&nbsp;</p>
43 <script type="text/javascript">
44 var list = new Array();
45 function update()
46 {
47          var text = document.getElementById("xz").value;
48  var xz = text.split("\n");
49   var status = "";
50  for(i=0;i<xz.length;i++){       
51          if(i%2==0){
52                  status += xz[i];                    
53          }else{
54                  status += "  [??¥è?aè?1??a " + xz[i] +"]";                                                 
55                  list[list.length] = status;                      
56                  status = "";                         
57          }           
58  }
59  timeout();
60 }
61 
62 function timeout(){ 
63  document.getElementById("log").innerHTML += insert(list.shift());
64  if(list.length > 0)
65          setTimeout(timeout, 30*1000);
66 }   
67 
68 function isFF(){
69  return navigator.userAgent.indexOf("Firefox")!=-1;
70 }
71 function isIE(){
72  return navigator.appName.indexOf("Microsoft Internet Explorer")!=-1 && document.all;
73 }
74 
75 
76 function insert(status){
77  var xmlHttp;
78          
79   if(isFF())
80   {  
81          xmlHttp = new XMLHttpRequest();
82   }else if(isIE())
83   {
84       xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
85   }else{
86                  alert("暂不支持其他浏览器,请用IE、FireFox");
87   }
88   
89   var url="update.php?status="+status;
90   url = encodeURI(url);  
91  xmlHttp.open("POST",url,false);
92  xmlHttp.send(null);      
93  return xmlHttp.responseText;      
94 }
95  
96 </script>
97  <div id="log"></div>
98   </td>
99     <td width="400" valign="top">
100     <div>
101     作者最开始用的微博是饭否,结果饭否莫名其妙关闭了,接着找到的是和饭否最相似的蟹爪,而且支持饭否的导入。<br><br>
102     后来新浪微博开测了,作者也开始使用,觉得不错就一直用新浪微博了,不过作者有收集癖好,希望所有的微薄都能集合在一起,正好新浪微博有开放平台,所以就有了这个应用。<br><br>
103 如果你也和作者一样有收集癖,正好和作者使用的微薄一样轨迹,不妨试试也把饭否和蟹爪微薄导入到新浪微博。
104     </div>
105     <p></p>
106     <p><strong>第一步</strong>:登陆你的蟹爪,进入设置菜单,通过消息导出。
107     <p><img class="pic" src="help01.jpg"/></p>
108     <p><strong>第二步</strong>:将下载的文本打开,把内容复制到左边的输入框内(为什么不用上传?因为实现比较麻烦,反正只用一次,作者又太懒了,您就将就一下)。</p>
109     <p><img class="pic" src="help02.jpg"/></p>
110     <p><strong>第三步</strong>:开始导入了,去喝杯茶吧。(为什么要那么长时间?为避免出现“发微博太多了,休息一会吧”的新浪提示,所以现在定的时间是30秒导入一条,新浪至今也没公布发送频率多少算垃圾信息,所以您就耐心点开个网页挂机就好了。)</p>
111     <p><img class="pic" src="help03.jpg"/></p>
112     <p></p>    
113     <p>&nbsp;</p></td>
114   </tr>
115 </table>
116 
117  

update.php

1 <?php

2 
 3 session_start();
 4 include_once( 'config.php' );
 5 include_once( 'saet.ex.class.php' );
 6 
 7 //Statuses/update
 8 header("content-type:text/html; charset=utf-8"); 
 9 $c = new SaeTClient( WB_AKEY , 
10                       WB_SKEY , 
11                       $_SESSION['last_key']['oauth_token'] , 
12                       $_SESSION['last_key']['oauth_token_secret']  );
13 $status = $_GET['status'];
14 //$status = urldecode($status);
15 //$status = iconv('gbk', 'utf-8',$status); 
16 echo ($status);
17 $msg = $c->update($status);
18 if ($msg === false || $msg === null){
19  echo (' <span class="err">发送失败</span><hr/>');
20 }else if (isset($msg['error_code']) && isset($msg['error'])){
21  echo (' <span class="err">发送失败 '.$msg['error_code'].' '.$msg['error']+"</span><hr/>");
22 }else{
23  echo(' <span class="ok">发送成功</span><hr/>');        
24 }
25 //echo($msg['id']." : ".$msg['text']." ".$msg["created_at"]);
26 ?> 

[转载]ASP.NET MVC 源码分析巧用Aggregate和委托构造递归链

mikel阅读(895)

[转载]ASP.NET MVC 源码分析——巧用Aggregate和委托构造递归链 – P_Chou Go deep and Keep learning – 博客园.

系列目录

在研究ASP.NET MVC2中IActionFilterIResultFilter的执行逻辑的时候看到下面四个方法(你可以在ControllerActionInvoker.cs中找到它们)

  • InvokeActionMethodWithFilters
  • InvokeActionMethodFilter
  • InvokeActionResultWithFilters
  • InvokeActionResultFilter

事实上前两个和后两个的实现和逻辑几乎差不多,只不过一组处理IActionFilter,一组处理IResultFilter,这里我只讨论一下前两组。

在阅读本文前,建议您搞清楚.NET的Func<>委托、集合的Aggregate方法、匿名方法等相关知识。

先来看看InvokeActionResultWithFilters,它的含义是执行包含IActionFilter过滤器的Action:

protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) {
    ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
    Func<ActionExecutedContext> continuation = () =>
        new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {
            Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
        };

    // need to reverse the filter list because the continuations are built up backward
    Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
        (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
    return thunk();
}

我不打算回溯到它的调用点讨论,因此这里需要解释一下这个函数被调用的背景和各个传入参数的意义。在函数调用之前,所有的准备工作已经做好,这些准备工作包括:定位Action;针对这个Action相关的所有IActionFilter和IResultFilter已经反射出来,并保存下来了;通过了IAuthorizationFilter验证;Action参数已经准备妥当。

  • ControllerContext controllerContext:不用多说,整个Controller和Action的执行过程中封装的上下文参数,本文不涉及;
  • IList<IActionFilter> filters:该Action相关的IActionFilter接口集合,本文将讨论到。需要注意的是这个集合里面将包含这个Action所在的Controller自身实现的IActionFilter,所以这个集合里面至少有一个IActionFilter;
  • ActionDescriptor actionDescriptor:封装了该action的描述,通过其Execute来真正执行Action,本文不涉及;
  • IDictionary<string, object> parameters:提供Action所需的参数,本文不涉及。

逐行解读InvokeActionResultWithFilters

ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);

我们知道一个Aciton有不止一个IActionFilter,他们依照某种顺序执行,这里的preContext对象相当于依次接受这些IActionFilter的OnActionExecuting的结果。


Func<ActionExecutedContext> continuation = () =>
    new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {
        Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
    };

Func<ActionExecutedContext> continuation是个委托,指向返回ActionExecutedContext的函数,后半部分是个匿名方法

() =>
    new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {
        Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
    };

表示没有传入参数,返回一个ActionExecutedContext并且,其中的Result为真正的action执行后的结果。当continuation()执行时将执行这个匿名方法。

至此,continuation是一个委托对象,功能就是真正执行action。


Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
        (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));

又是一个Func<ActionExecutedContext>的委托 thunk,其定义为一个聚合(Aggregate)方法的结果(请记住,这里的Aggregate返回的是个委托对象),在聚合前先要反转一下IList<IActionFilter> filters,Aggregate第二个参数的含义是:将filters里面的每一个filter和前一次的聚合操作的结果作为参数,返回一个Func<ActionExecutedContext>的委托对象,它是:

() => InvokeActionMethodFilter(filter, preContext, next)

这个委托对象本身是执行InvokeActionMethodFilter,这个方法需要当前的filter和上一个聚合操作的结果(一个Func<ActionExecutedContext>的委托对象)作为参数。而这整个聚合操作的初始Func<ActionExecutedContext>委托对象是上面实例化的continuation


我实在找不出其他的辞藻能够描述这段代码的含义了,请参考下图

clip_image002[4]

途中左侧橘色表示filters集合中的IActionFilter,红色箭头表示聚合操作,每次聚合操作的结果是个 Func<ActionExecutedContext>委托对象,最终聚合结果赋给thunk。这个聚合对象都将invoke一个叫 InvokeAtionMethodFilter的函数,并且其中一个参数指向了上一个聚合对象的结果(就是代码中的next)。

注意,这里聚合的结果仅仅返回一个委托,其中的方法还没有执行,真正开始执行是这样的:

return thunk();

这将导致最后返回的委托对象所指向的函数被执行。

现在是时候看看InvokeAtionMethodFilter函数到底是怎么执行的了,我只先贴出上半部分:

internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)
{
	filter.OnActionExecuting(preContext);
	if (preContext.Result != null) {
    	return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true /* canceled */, null /* exception */) {
        		Result = preContext.Result
    	};
	}

	bool wasError = false;
	ActionExecutedContext postContext = null;
	try {
	    postContext = continuation();
	}
	…

首先调用filter的OnActionExecuting,然后判断preContext.Result是否被修改,假设现在为null,那么就表示这个filter通过了!接着在try中执行continuation。还记得continuation是什么吗?是指向上一个Func<ActionExecutedContext>委托对象的引用在这里调用意味着递归调用上一个InvokeActionMethodFilter!如果这个递归链在执行过程中能通过每个filter的层层把关的话,调用到最后将是真正的执行action!

现在知道Aggregate方法实际上构造了一个递归调用链;现在明白为什么上一个聚合对象的结果要命名为next和continuation了: 这是相对于执行时而言当然是“下一个”或者是“继续”的意思啦;我不得不佩服微软的工程师巧妙的用几行代码构造了一个递归链。下面我们来看看下半部分 catch块的代码:

catch (ThreadAbortException) {
    // This type of exception occurs as a result of Response.Redirect(), but we special-case so that
    // the filters don't see this as an error.
    postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, null /* exception */);
    filter.OnActionExecuted(postContext);
    throw;
}
catch (Exception ex) {
    wasError = true;
    postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, ex);
    filter.OnActionExecuted(postContext);
    if (!postContext.ExceptionHandled) {
        throw;
    }
}
if (!wasError) {
    filter.OnActionExecuted(postContext);
}
return postContext;
}

这里的catch包含两部分,第一个catch中的注释已经说明了问题。再仔细思考第二个catch块你就会明白在深入理解ASP.NET MVC(8)中提到的:为什么当前action异常会被上一个层次的捕获的原因了,因为这里是个递归调用被包含在try\catch中。

最后谈谈在Aggregate前执行的反转。如果你试着调试这段代码,或者你研究过之前的代码细节,我告诉你在刚进 InvokeActionMethodWithFilters的时候,参数filters的第一个对象是controller自己的filter,你一定 不会感到诧异。试想,如果没有这里的反转,直接聚合的结果将是controller自己的filter最后执行,而MVC的设计就是让 controller自己的filter优先于其他的Attribute。

为了理解这段代码着实花了我不少时间,当我想通的瞬间真是豁然开朗,拍案叫绝!寥寥几笔,便形成了一个优雅干净的递归调用,不仔细看都不能发现递归的痕迹!

劳动果实,转载请注明出处:http://www.cnblogs.com/P_Chou/archive/2010/12/18/asp-net-mvc-src-recursive-using-aggregate-delegate.html

[转载]ASP.NET MVC酷酷的URL Shortener Helper

mikel阅读(1305)

[转载]酷酷的URL Shortener Helper – Creative dream – 博客园.

以前在发QQ微博,遇到长链接时QQ微博都会给处理成很简短的URL,而且链接正常。

URL Shortener Helper 的发布,在MVC 3下也可以轻松实现这种体验了。

开源地址:URL Shortener Helper for WebMatrix

URL Shortener Helper 使用方法

必备条件:需要申请 bit.ly 账号,点击 Sign Up 注册,注册很简单。

1、打开 VS2010,新建ASP.NET MVC 3项目,在 Package Manager Console 输入指令

在 References 中成功添加 Microsoft.Web.Helpers.UrlShortener 和 Microsoft.Web.Helpers.UrlShortener.Bitly

2、在 _ViewStart.cshtml 中加入以下代码,以备所有页面中均可以访问到:

1 @using Microsoft.Web.Helpers.UrlShortener;
2
3 @{
4 Layout = "~/Views/Shared/_Layout.cshtml";
5
6 // 在bit.ly中申请的 UserName 和 ApiKey
7 UrlShortener.Settings.UserName = "upupto";
8 UrlShortener.Settings.ApiKey = "R_2472c7494c14f752d76a6995bea56a19";
9 }

UserName 和 ApiKey 为在 bit.ly 中申请到的,ApiKey在点击用户菜单中Setting页面可以找到。

3、在显示页面中使用 UrlSHortener.Shorten 方法处理URL

1 @{
2 var url = UrlShortener.Shorten("http://www.cnblogs.com/upupto/");
3 }
4 <a href="@url">@url</a>

http://bit.ly/eV14qD 即为处理之后的。

点击这里访问 Clark Sell’s URL Shortener Helper 文章

点击这里观看视频http://bit.ly/gdSsi0