[转载]Delphi组件开发教程指南目录

mikel阅读(1046)

[转载]Delphi组件开发教程指南目录 – 得闲笔记 – 博客园.

用Delphi开发的时间也不短了!刚接触Delphi的时候,就觉得组件这个东西非常方便!根本不必知道组件内部的作为,只要使用就好了!然而用的多 了,也不免会对各种delphi组件的内部实现方式产生兴趣!也不知道从什么时候开始,开始开发delphi的控件,这也得归功于我所在的公司了,由于老 板的信任,我得以开发各种公司内部需要的控件,期间也积累了一部分的开发经验。在这个Delphi日渐凋零的时刻,于是我在心里便想,用了这么长时间的 Delphi,也用来混了好几年的饭钱了,同时也不断的在网络上汲取了各种各样的高手的代码与经验,该是时刻回报一下网络的Delphi界同胞,让更多人 参与到这个行列中来!

虽说,题目是叫教程指南,其实也仅仅作为一个学习心得交流,提供给暂时只会使用托控件进行Delphi应用程序开发的,而又想学习一下这方面知识的人,一 个摸索的捷径!高手或可对内容不屑,飘过就可,各种代码仅供初学者入门,所以一定会尽量就简,同时尽量将我所熟悉的各种Windows消息以及触发条件和 消息过程都简述出来!

本系列教程完全为本人原创,本人享有示例源码的所有 权并与博客园共同享有该教程版权,请在本人许可的前提下进行相关使用,否则保留追究法律责任的权利。

教程目录:

Delphi组件开发教程指南(1)组件开发概述

Delphi 组件开发教程指南(2)简单扩充TEdit

Delphi 组件开发教程指南(3)组件注册

Delphi 组件开发教程指南(4)组件生成过程(针对TWinControl继承而来的组件)

Delphi 组件开发教程指南(5)实现类QQ的编辑框

作者:不得闲
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必 须保留此段声明,且在文章页面明显位置给出原
文连接,否则保留追究法律责任的权利。

[转载](推荐)asp.net mvc强大的分页控件MvcPager

mikel阅读(909)

[转载](推荐)asp.net mvc强大的分页控件MvcPager – longgel – 博客园.

不管使用什么来开发程序,都少不了需要做分页,目前使用ASP.NET mvc开发的web应用程序的人越来越多了,相应的辅助,提高开发效率的helper方法、控件都将会出现。今天我向大家介绍一款在ASP.NET mvc框架中使用的分页控件。本人也是在新年的时候初次使用,但是一直没有推荐给大家。利用五一休息时间也就介绍给大家。声明我与博杨计算机有限公司无任 何关系只是觉得这个分页控件很好用,并且功能强大,在这里是真的只为介绍这款分页控件。

另外下载地址:http://mvcpager.codeplex.com/releases/view/42912

另外还有相关使用的DEMO也很丰富,上面的网址也可以下载非常完整的DEMO。

DEMO里有使用各种在ASP.NET MVC中提倡的方式来实现分页功能,分别有:

1.标准的Url分页 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/Demo

2.JQuery ajax分页 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/AjaxDemo

3.Microsoft Ajax分页 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/MicrosoftAjaxDemo

4.使用DataRow集合分页 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/DataRowsPaging

5.ASP.NET MVC Pager分页控件用户自定义信息 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/CustomInfo

6.MvcPager应用CSS样式 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/ApplyStyles

7.保持Url参数(分页恢复Url参数) 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/UrlParameters?year=2009&month=12&author=webdiyer

8.ajax正在加载效果分页 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/Loading

9.使用自定义路由表实现分页 在线演示效果请看:http://www.webdiyer.com/Controls/MvcPager/CustomRouteTable/employee_1/page_1

10.MvcPager使用存储过程分页 http://www.webdiyer.com/Controls/MvcPager/StoredProcedure

11.ASP.NET MvcPager Ajax产生异常处理分页 http://www.webdiyer.com/Controls/MvcPager/AjaxEvents

12.MvcPager使用输入或选择页索引并跳转实现分页 http://www.webdiyer.com/Controls/MvcPager/PageIndexBox

大家可以根据自己的实际情况选择使用那种分页方式或者同时使用几种分页方式。

MvcPager的介绍

MvcPager分页控件是在ASP.NET MVC Web应用程序中实现分页功能的一系列扩展方法,该分页控件的最初的实现方法借鉴了网上流行的部分源代码,尤其是ScottGu的 PagedList<T>类和相关方法,经过站长不断完善和改进后推出的比较成熟而且功能强大的ASP.NET MVC分页解决方案。

MvcPager主要功能有:

  1. 实现最基本的url route分页;
  2. 支持手工输入或选择页索引并对输入的页索引进行有效性验证;
  3. 支持使用ASP.NET MVC Ajax默认的MicrosoftAjax和MicrosoftMvcAjax客户端脚本库实现Ajax分页;
  4. 支持使用JQuery实现Ajax分页,生成的Html代码更精简;
  5. 支持Ajax分页模式下,若客户端浏览器不支持或禁用JavaScript功能时安全降级为普通分页
  6. 搜索引擎友好,无论是普通分页还是Ajax分页,搜索引擎都可以直接搜索到所有页面。
  7. 支持ASP.NET MVC 1.0和最新的ASP.NET MVC 2.0 版本;
  8. 支持IE、Firefox、Opera、Chrome及Safari等常用浏览器;

MvcPager分页控件仍在不断开发完善中,更多功能将在以后的升级版本中得到增强和完善,希望您在使用过程中提出您的宝贵意见和建议!

所有中文资料都在http://www.webdiyer.com/Controls/MvcPager

[转载]WF4.0实战(十二):ASP.NET MVC2.0结合WF4.0实现用户多步注册流程

mikel阅读(780)

[转载]WF4.0实战(十二):ASP.NET MVC2.0结合WF4.0实现用户多步注册流程 – 海纳百川 – 博客园.

这篇文章结合ASP.NET MVC和WF4.0实现一个简单的用户多步注册。用户注册分了四步骤。流程图如下:

zhuche

第一步:填写个人信息:

step1

第二步:填写职位信息:

step2

第三步:填写学历信息:

step3

第四步:填写联系信息:

step4

第五步骤:完成

step5

WF4.0状态机如下图:

step6

每一步点击Next跳到下一步,点击Back回到上一步。

实现:

第一步:新建一个ASP.NET MVC Application和一个Workflow的ActivityDesignerLibrary项目,在mvc项目的Model文件夹下添加一个 User。代码如下:

1 public class User
2 { //个人信息
3 [Required(ErrorMessage = 姓名不能为空)]
4 [StringLength(20, ErrorMessage = 姓名长度不能超过20个字符)]
5 public string Name { get; set; }
6 public int? Age { get; set; }
7 //职位信息
8 [Required(ErrorMessage = 职位不能为空)]
9 public string Post { get; set; }
10 public int? Salary { get; set; }
11 //学历信息
12 [Required(ErrorMessage = 毕业院校不能为空)]
13 public string University { get; set; }
14 public int? GraduationYear { get; set; }
15 //联系信息
16 [Required(ErrorMessage = 邮件不能为空)]
17 [RegularExpression(@”^[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z| + @”0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*\.([a-z] + @”[a-z|0-9]*(\.[a-z][a-z|0-9]*)?)$, ErrorMessage= 邮件格式不正确)]
18 public string Email { get; set; }
19 public int? Mobile { get; set; }
20 }
21

第二步:在Controllers中添加一个控制类,代码如下:

1 public class UserController : Controller
2 {
3 //
4 // GET: /User/
5 #region Declarations
6 static WorkflowUtil wrkFlw = null;
7 string page=Step1;
8 public User userObj;
9 #endregion
10 #region Process action method
11 public ActionResult Process(string nextButton, string backButton)
12 {
13 if (wrkFlw == null )
14 {
15 wrkFlw = new WorkflowUtil();
16 }
17 if ((nextButton != null))
18 {
19 page = wrkFlw.RunWorkflow(Next);
20 return View(page, userObj);
21 }
22 else if (backButton != null)
23 {
24 ModelState.Clear();
25 page = wrkFlw.RunWorkflow(Prev);
26 return View(page, userObj);
27 }
28 else
29 return View(page, userObj);
30 }
31 #endregion
32 #region Events
33 protected override void OnActionExecuting(ActionExecutingContext filterContext)
34 {
35 userObj = (User)TempData[User];
36 if (userObj == null) userObj = new User();
37 TryUpdateModel(userObj);
38 if (TempData[CurrentPage] != null) page = TempData[CurrentPage].ToString();
39 }
40 protected override void OnResultExecuted(ResultExecutedContext filterContext)
41 {
42 TempData[User] = userObj;
43 TempData[CurrentPage] = page;
44 }
45 #endregion
46 public ActionResult Index()
47 {
48 return View();
49 }
50 }

第三步:在方法Process上选择添加视图,如下图选择:

step11

如此共生成五个view页面:step1.step2,step3,step4,step5,Final。

第四步:设计状态机工作流。这里只演示step1的设置,如下图:

step1111

step11122

总结:使用WF完美结合ASP.NET mvc实现这个功能。

代码:/Files/zhuqil/mvc.rar

作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转载]StringTemplate.Net 学习笔记(总结)

mikel阅读(868)

[转载]StringTemplate.Net 学习笔记(总结) – 囧月 – 博客园.

这是我第一次接触模板引擎,也是第一次这么认真的去写一个系列,ST有些概念跟实际的编程语言差不多,通过对ST学 习,对编程语言也有了一点新的认识。

StringTemplate.Net 学习笔记(1):开篇

StringTemplate.Net 学习笔记(2):语法介绍(表格)

StringTemplate.Net 学习笔记(3):表达式元素语法(上)

StringTemplate.Net 学习笔记(4):表达式元素语法(下)

StringTemplate.Net 学习笔记(5):条件声明

StringTemplate.Net 学习笔记(6):自定义输出格式

StringTemplate.Net 学习笔记(7):加载模板文件

StringTemplate.Net 学习笔记(8):加载模板组文件

StringTemplate.Net 学习笔记(9):深入了解模板组文件

StringTemplate.Net 学习笔记(10):模板组继承及模板组接口

StringTemplate.Net 学习笔记(11):自定义错误处理

由于ST资料比较少,所以基本上都是参照http://www.antlr.org/wiki/display/ST/StringTemplate+Documentation以 及源代码,在对官方文档(话说官方文档也有点古老)不断印证过程中,对文章进行修正、补充。

水平所限,很多地方表达的不到位,也因此贴 了许多代码-_-。

作者:囧月
出处:http://lwme.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转载]用SQL做单位换算

mikel阅读(1334)

[转载][原]用SQL做单位换算 – killkill – 博客园.

pumeifen朋友在首页提出了一个问题“SQL 问题 求解”,我对这个问题延伸一下描述为“用数据库来做单位换算”,以长度单位为例,常用的长度单位 有:毫米、厘米、分米等等,而英制的长度单位有英寸、英尺、码等,而我国传统的长度单位也有寸、尺、丈等等。

小学时学习单位换算的基本 算法都是将他们转换成同一个长度单位然后再换算的,我借鉴这个算法写下此文。

首先在Oracle中构建一个长度单位的转换表:

1 create table Length
2 (
3 name varchar2(50),
4 ratio number(10,5) not null,
5 parent varchar2(50),
6 constraints pk_length primary key (name)
7 )

插入测试数据:

01 insert into Length
02 ---- 国际标准的长度单位
03 select '毫米' ,1.0 ,null from dual union all
04 select '厘米' ,10.0 ,'毫米' from dual union all
05 select '分米' ,10.0 ,'厘米' from dual union all
06 select '米' ,10.0 ,'分米' from dual union all
07 select '千米' ,1000.0 ,'米' from dual union all
08 ---- 我国传统的长度单位
09 select '寸' ,3.33,'厘米' from dual union all
10 select '尺' ,10.0 ,'寸' from dual union all
11 select '丈' ,10.0 ,'尺' from dual union all
12 ---- 少数欧美国家使用的英制长度单位
13 select '英寸' , 2.54 , '厘米' from dual union all
14 select '英尺' , 12.0  , '英寸' from dual union all
15 select '码' , 3.0  , '英尺' from dual union all
16 select '浪' , 220.0  , '码' from dual union all
17 select '英寻' , 2.0  , '码' from dual union all
18 select '英里' , 1760.0  , '码' from dual

这个Length表实际上保存的是一棵树,简单表示如下:

image

如果,我想知道1英里=?千米,Oracle可以使用connect by …. start with 分别进行查询得从千米和英里到毫米之间的路径:

01 SELECT name,ratio,parent
02 FROM length
03 CONNECT BY nocycle PRIOR parent = name
04 START WITH name = '千米'
05 union all
06 select null,null,null from dual
07 union all
08 SELECT name,ratio,parent
09 FROM length
10 CONNECT BY nocycle PRIOR parent = name
11 START WITH name = '英里'
01 NAME            RATIO PARENT
02 ---------- ---------- ----------
03 千米             1000 米
04 米                 10 分米
05 分米               10 厘米
06 厘米               10 毫米
07 毫米                1
08
09 英里             1760 码
10 码                  3 英尺
11 英尺               12 英寸
12 英寸             2.54 厘米
13 厘米               10 毫米
14 毫米                1

接下来只需要将千米和英里转换成毫米就可求比率了,SQL语句如下:

01 select
02 ( --英里转化成毫米
03 select exp(sum(ln(ratio)))
04 FROM length
05 CONNECT BY nocycle PRIOR parent = name
06 START WITH name = '英里'
07 )/( --千米转化成毫米
08 select exp(sum(ln(ratio)))
09 FROM length
10 CONNECT BY nocycle PRIOR parent = name
11 START WITH name = '千米'
12 ) "英里:千米"
13 from dual;
1 英里:千米
2 ----------
3 1.609344

这里有个小插曲,SQL中没有计算累积的聚合函数,需要变换一下才能算到累积的结果,详细可以看我写的一篇博文[原] 计算乘积的聚合函数跑哪去了呢?

SQL Server 2005/2008中,可以使用CTE的语法,以下省略在SQL Server中创建测试表Length的过程。

01 WITH LengthTree
02 as
03 (
04 select name,ratio,parent,0 as level from Length
05 where name = '千米'
06 union all
07 select l.name,l.ratio,l.parent,level+1
08 from LengthTree t
09 inner join Length l
10 ON l.name=t.parent
11 )
12 select * from LengthTree

image

稍微变换一下,我将英里、千米到毫米之间的路径列出来:

01 ;WITH LengthTree
02 as
03 (
04 select name,ratio,parent,0 as level,name as start from Length
05 where name in ( '千米' , '英里' )
06 union all
07 select l.name,l.ratio,l.parent,level+1,t.start
08 from LengthTree t
09 inner join Length l
10 ON l.name=t.parent
11 )
12 select * from LengthTree
13 order by start,level

image

最后,就是再变换一下求解英里和千米之间的比率啦,SQL 如下:

01 ;WITH LengthTree
02 as
03 (
04 select name,ratio,parent,0 as level,name as start from Length
05 where name in ( '千米' , '英里' )
06 union all
07 select l.name,l.ratio,l.parent,level+1,t.start
08 from LengthTree t
09 inner join Length l
10 ON l.name=t.parent
11 )
12 select (
13 select exp(sum(log(ratio))) from LengthTree where start='英里'
14 )/(
15 select exp(sum(log(ratio))) from LengthTree where start='千米'
16 ) as "英里:千米"

image

看到这里,可能有朋友会问,如果我求1英里=?浪,比较好的做法是都转换成码然后再做运算,但是按照这个算法英里和浪都会最终转换成毫米再进行运 算,中间极有可能产生精度问题,而且运算量明显多很多。

是的,解决运算量的重点在于找到“千米路径”和“英里路径”的相交点,两条路径一旦相交,再往根节点“毫米”走下去的路径都是多余的(沿用上文,从 “千米”到“毫米”的路径称为“千米路径”,从“英里”到“毫米”的路径称为“英里路径”)。

虽然,通过集合的并、交、差可剔除多余的路径,但SQL变得非常长篇累赘,而且需要读取的块/页数不见减少,于是作罢,如果大家有兴趣,可以自己写 写,希望您有更好的解决方法。至于精度问题,我的意见是,不要偏太多就行了…….

希望本文对您有帮助。

长度单位主要参考百度百科的长度单位wiki 的英制单位

[转载]Delphi 组件开发教程指南(4)组件生成过程(针对TWinControl继承而来的组件)

mikel阅读(904)

[转载]Delphi 组件开发教程指南(4)组件生成过程(针对TWinControl继承而来的组件) – 得闲笔记 – 博客园.

还记得在第二章的时候,我用到了procedure CreateParams(var Params: TCreateParams);这个函数的吧!为什么我会使用这个函数来实现那个对齐的问题呢!现在就来追根底的来看看!这个过程其实是在构建窗口的时候 会调用的,当然我说的这个是针对TWincontrol继承过来的组件说的,从TGraphicontrol等继承过来的是没有这个的。这个函数的产生也 是Windows组件库所特有的,如果列为看官有Windows编程的基础,那么这个就很容易理解了,记得,在Windows编程的时,注册这个窗口类之 前,我们都会为一个窗口类指定一系列的参数,而这个CreateParams函数就是产生在这个注册过程之前,目的是用来为创建过程指定参数。

在讲CreateParams的来源之前,我们必须简略说说组件由生成到显示在用户面前的这个过程。这是个灰常纠结的问题,纠结到我不晓得怎么去说(当然 纠结的主要原因还是本人的水平有限,下面大家就简单看看吧,解说可能有错,欢迎指正)。由于组件都是依托于Form之上的,所以组件要显示出来最首要的是 要组件所依托的容器显示出来,那么最首要,我们需要看看Form的创建然后显示出来的过程。至于窗口的创建过程可以参考一下黄 叉叉的博客,在这里我在给他的细化一下,便于我们的工作的展开!这个细化应该是在他那个说明的第5步之前,也就是他说的

此处说明一下:


对 TWinControl 的 Handle 属性的读取会触发 TWinControl.GetHandle;

可以察看 Property Handle; 的声明。


5、第四步中对 Handle 进行读取,触发下述序列:(TWinControl)

Handle->GetHandle->HandleNeeded

这个HandleNeeded是在什么时候第一次调用的,其实他不是在GetHandle的时候第一次调用的,而是在窗口显示出来之前,也就是 Visible变化的过程中第一次调用的,而这个Visible的变化,是在Delphi读取Form资源文件的属性了之后触发(这个属性读取过程,可以 参考Delphi 的持续机制浅探)。我们看看Visible这个属性变化所触发的过程,这个属性定义在TControl中,属性变化对应的过程为

procedure TControl.SetVisible(Value: Boolean); begin if FVisible <> Value then begin VisibleChanging; FVisible := Value; Perform(CM_VISIBLECHANGED, Ord(Value), 0); RequestAlign; end; end;

由此可以看到在属性变化的时候发送了一个CM_VISIBLECHANGE的消息出去,然后我们再去这个消息的触发过程

procedure TWinControl.CMVisibleChanged(var Message: TMessage); begin if not FVisible and (Parent <> nil) then RemoveFocus(False); if not (csDesigning in ComponentState) or (csNoDesignVisible in ControlStyle) then UpdateControlState; end;

本过程在TControl中也有,但是在TWinControl中被重写了,所以我这里只列出了TWinControl的,在Visible变化的时候会 调用UpdateControlState函数来更新控件状态,然后这个更新过程中调用了另外一个更新控件显示的函数UpdateShowing,我们来 看看UpdateShowing这个过程

procedure TWinControl.UpdateShowing; var ShowControl: Boolean; I: Integer; begin ShowControl := (FVisible and (not (csDesigning in ComponentState) or not (csDesignerHide in ControlState)) or ((csDesigning in ComponentState) and not (csDesignerHide in ControlState)) and not (csNoDesignVisible in ControlStyle)) and not (csReadingState in ControlState) and not (csDestroying in ComponentState); if ShowControl then begin //这个时候如果是第一次显示,FHandle为0,就会调用CreateHandle来创建一个窗口句柄了,也就是说 //在这个时候才真真实实的创建Windows的标准控件! if FHandle = 0 then CreateHandle; if FWinControls <> nil then for I := 0 to FWinControls.Count - 1 do TWinControl(FWinControls[I]).UpdateShowing;//之后会更新属于这个控件容器的所有子控件显示 end; if FHandle <> 0 then if FShowing <> ShowControl then begin FShowing := ShowControl; try SetPerformingShowingChanged(Self); try Perform(CM_SHOWINGCHANGED, 0, 0); finally ClearPerformingShowingChanged(Self); end; except FShowing := not ShowControl; raise; end; end; end;

CreateHandle过程中调用了CreateWnd,然后CreateWnd得时候就调用我们上面声明的CreateParams来为标准控件传递 参数。上面说了控件的最终容器Form的创建到显示过程,那么我们现在再来说说一般控件的创建显示过程,其实也就和TForm的创建显示过程一样!只是 TForm的显示从读取了属性之后触发,而一般控件由他所在的容器触发,也就是上面的UpdateShowing过程中的实现过程,后面会遍历子控件,然 后更新他们的显示,第一次显示的时候都会触发CreateHandle的过程,所以Windows组件的真实创建过程实际上应该是在组件的第一次显示的过 程中创建,而不是我们调用Create的时候,在Delphi中,我们Create的时候,仅仅是为这个组件提供了一些初始化信息以及各种参数而已。说到 这里,那么,第二章中的CreateParams的实现方法也就相当顺其自然了,因为在CreateParams中为Edit指定其他的扩展样式时,实际 上Windows的真实Edit控件实际上还没有创建出来。那么当指定了新样式,当他创建出来的时候,就自然具备了我们指定的扩展样式了。然后,我在设置 新样式的时候,调用了一个RecreateWnd的方法,这个方法的目的是重建句柄,也就是重建Windows组件,这个函数的实现过程相当简单,仅仅就 是发送了一个组件重建的消息CM_RECREATEWND,然后我们看看这个消息过程的实现方法

procedure TWinControl.CMRecreateWnd(var Message: TMessage); var WasFocused: Boolean; begin WasFocused := Focused;//先保存控件是否是焦点状态 UpdateRecreatingFlag(True);//这个函数,我就不贴他的代码了,从他的代码中,我们可以看出来,这个函数 //的目的是为所有的子控件打上重建的标记 try DestroyHandle;//释放句柄,同时释放所有子控件的句柄 UpdateControlState;//更新控件状态,这个函数上面已经分析,会建立句柄,同时子控件句柄。 finally UpdateRecreatingFlag(False);//重建状态完成 end; if WasFocused and (FHandle <> 0) then Windows.SetFocus(FHandle);//如果重建成功,并且原先有焦点,就恢复原先的焦点状态 end;

可见,这个重建的过程,如果你是一个容器控件,内部有很多子控件的话,使用这个方式来实现某些效果,效率是灰常低下的,所以容器类不建议频繁使用重建方 法!

至此为止,组件的生成过程就讲解完毕,欢迎专家指正!

组 件教程指南目录

作者:不得闲
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必 须保留此段声明,且在文章页面明显位置给出原
文连接,否则保留追究法律责任的权利。

[转载]Quest.Central.For.Databases——SQL Tuning for SQL Server

mikel阅读(1139)

[转载]【推荐】[SQL优化工具]Quest.Central.For.Databases——SQL Tuning for SQL Server – Beyond the dream——飛雪飄寒 – 博客园.

随着企业数据库的急剧膨 胀和日益复杂,DBA为保证数据库性能所付出的努力与日俱增,手工或使用 多种无法集成的管理工具,都会给日常管理和维护带来不必要的困难。 Quest Central for Databases 是一种集成化、图形化、跨平台的数据库管理解决方案,可以管理异构环境下的 OracleDB2 SQL server 数据库。Quest Central for Databases 消除了企业IT人员管理多种数据库时面临的技术障碍,提高了IT人员工作效率,改善了数据库性能和数据库应用的可用性。为灵活满足用户的不同需求,Quest Central for Databases 采用了模块化产品架构。

该产品包括下列功能模块:

1. 数据库管理(DBA

2. 数据库监控(Monitoring Pack

3. 数据库诊断 (Spotlight Diagnostics)

4. 数据库分析 (Database Analysis)

5. SQL优化 (SQL Tuning)

6. 空间管理 (Space Management)

7. 压力测试 (Load Generator)

8. 数据生成 (Data Generator)

9. PL/SQL 开发 (TOAD)

10. 专家建议 (Knowledge Expert)

今天主要介绍其中的SQL优化工具—— SQL Tuning for SQL Server

一、SQL Tuning for SQL Server简介

SQL语句的优化对发挥 数据库的最佳性能非常关键。然而不幸的是,应用优化通常由于时间和资源的因素而被忽略。SQL Tuning (SQL优化)模块可以对比 和评测特定应用中SQL语句的运行性能,提出智能化的优化建议,帮助用户 改善应用的响应时间。SQL优化模块具有非介入式SQL采集、自动优化和专家建议等功能,全面改善SQL优化工作。

二、SQL Tuning for SQL Server的使用

1、打开Quest Database Management Solutions弹出窗口如图1所示

1

2、在红色标记处打开SQL Tuning 优化SQL

1)建立连接。

Quest Central主界面上的“Database”树上选择“SQL Server”,然后在下方出现的“Tools”框中选择“SQL Tuning”选项,打开“Lanch SQL Tuning for SQL Server Connections”对话框(图2、图3)。我们在这 里建立数据库服务器的连接,以后的分析工作都会在它上面完成。

2 “建立连接”对话框

3

双击“New Connection”图标,在弹出窗口中输入数据库的信息,单击“OK”,然后单击“Connect”即可。

2)分析原始SQL语句 ,在单击“Connect”后将弹出一个新窗口,如图4

4

在打开窗口的“Oriangal SQL”文本框内输入需要分析的原始SQL语句,红色标记处选择对应的数据库名,SQL语句代码如下:

原始SQL语句

SELECT dbo.Person_BasicInfo.*, dbo.Graduater_GraduaterRegist.RegistNO AS RegistNO,
dbo.Graduater_GraduaterRegist.RegistTime
AS BaoDaoTime,
dbo.Graduater_GraduaterRegist.RegistMan
AS RegistMan,
dbo.Graduater_Business.ComeFrom
AS ComeFrom,
dbo.Graduater_Business.Code
AS Code, dbo.Graduater_Business.Status AS Status,
dbo.Graduater_Business.ApproveResult
AS ApproveResult,
dbo.Graduater_Business.NewCorp
AS NewCorp,
dbo.Graduater_Business.CommendNumber
AS CommendNumber,
dbo.Graduater_Business.EmployStatus
AS EmployStatus,
dbo.Graduater_Business.NewCommendTime
AS NewCommendTime,
dbo.Graduater_Business.GetSource
AS GetSource,
dbo.Graduater_Business.EmployTime
AS EmployTime,
dbo.Graduater_Business.Job
AS Job, dbo.Graduater_Business.FillMan AS FillMan,
dbo.Graduater_Business.FillTime
AS FillTime,
dbo.Graduater_Business.IsCommendOK
AS IsCommendOK,
dbo.Graduater_Business.ApproveUser
AS ApproveUser,
dbo.Graduater_Business.ApproveTime
AS ApproveTime,
dbo.Graduater_Business.RegistTime
AS RegistTime,
dbo.Graduater_Business.EmployCorp
AS EmployCorp,
dbo.Graduater_Business.JobRemark
AS JobRemark,
CASE WHEN dbo.Graduater_Business.ComeFrom = WS THEN 网上登记 WHEN dbo.Graduater_Business.ComeFrom
= HP THEN 华普大厦 WHEN dbo.Graduater_Business.ComeFrom = JD THEN 精典大厦
WHEN dbo.Graduater_Business.ComeFrom = MC THEN 赛马场 WHEN ComeFrom =
ZX THEN 高指中心 END AS ComeFromName,
dbo.Person_Contact.Address
AS Address, dbo.Person_Contact.Zip AS Zip,
dbo.Person_Contact.Telephone
AS Telephone, dbo.Person_Contact.Mobile AS Mobile,
dbo.Person_Contact.Email
AS Email, dbo.Person_Contact.IM AS IM,
dbo.Person_Skill.ForeignLanguage
AS ForeignLanguage,
dbo.Person_Skill.ForeignLanguageLevel
AS ForeignLanguageLevel,
dbo.Person_Skill.CantoneseLevel
AS CantoneseLevel,
dbo.Person_Skill.MandarinLevel
AS MandarinLevel,
dbo.Person_Skill.Language
AS Language,
dbo.Person_Skill.TechnicalTitle
AS TechnicalTitle,
dbo.Person_Skill.ComputerLevel
AS ComputerLevel,
dbo.Person_EmployPurpose.JobType
AS JobType,
dbo.Person_EmployPurpose.Vocation
AS Vocation,
dbo.Person_EmployPurpose.JobPlace
AS JobPlace,
dbo.Person_EmployPurpose.Salary
AS Salary,
dbo.Person_EmployPurpose.OnJobDate
AS OnJobDate,
dbo.Person_EmployPurpose.CorpType
AS CorpType,
dbo.Person_EmployPurpose.Job
AS RequireJob, YEAR(GETDATE())
YEAR(dbo.Person_BasicInfo.Birthday) AS Age,
dbo.Graduater_Business.EmployType
AS EmployType,
dbo.Graduater_Business.EmployTypeCode
AS EmployTypeCode,
dbo.Graduater_Business.EmployCorpType
AS EmployCorpType,
CASE WHEN dbo.Graduater_Business.PrintStatus = 已打印 THEN 已打印 ELSE 未打印
END AS PrintStatus, dbo.Graduater_Business.PrintTime AS PrintTime,
CASE WHEN dbo.Graduater_Business.EmployStatus = THEN 已就业 ELSE 未就业
END AS EmployStatusView
FROM dbo.Person_BasicInfo INNER JOIN
dbo.Graduater_Business
ON
dbo.Person_BasicInfo.PersonID
= dbo.Graduater_Business.PersonID LEFT OUTER JOIN
dbo.Graduater_GraduaterRegist
ON
dbo.Graduater_Business.GradBusinessID
= dbo.Graduater_GraduaterRegist.GraduaterGUID
INNER JOIN
dbo.Person_Contact
ON
dbo.Person_BasicInfo.PersonID
= dbo.Person_Contact.PersonID INNER JOIN
dbo.Person_Skill
ON
dbo.Person_BasicInfo.PersonID
= dbo.Person_Skill.PersonID INNER JOIN
dbo.Person_EmployPurpose
ON
dbo.Person_BasicInfo.PersonID
= dbo.Person_EmployPurpose.PersonID

然后点击工具栏上的“Execute”按钮,执行原始的SQL语句,SQL Tuning会自动分析SQL的执行计划,并把分析结果显示到界面上(图5)。

5 分析原始SQL语句

3)优化SQL

现在我们点击工具栏上的“Optimize Statement”按钮,SQL Tuning开始优化SQL,完成后,可以看到SQL Tuning产生了19条与原始SQL等价 的优化方案(图6)。

6 SQL优化 方案

4)获得最优SQL

接下来,我们来执行上面产生的优化方案,以 选出性能最佳的等效SQL语句。在列表中选择需要执行的优化方案(默认已全部选中), 然后点击工具栏上的“Execute”按钮旁边的下拉菜单,选择“Execute Selected”。等到所有SQL运行完成后,点击界 面左方的“Tuning Resolution”按钮,
可以看到 最优的
SQL已经出来啦,运行时间竟然可以提高21%!(图7

7 Tuning Resolution”界面

最优的SQL语句如下:

优化后的SQL语句

SELECT dbo.Person_BasicInfo.*,
dbo.Graduater_GraduaterRegist.RegistNO
AS RegistNO,
dbo.Graduater_GraduaterRegist.RegistTime
AS BaoDaoTime,
dbo.Graduater_GraduaterRegist.RegistMan
AS RegistMan,
dbo.Graduater_Business.ComeFrom
AS ComeFrom,
dbo.Graduater_Business.Code
AS Code,
dbo.Graduater_Business.Status
AS Status,
dbo.Graduater_Business.ApproveResult
AS ApproveResult,
dbo.Graduater_Business.NewCorp
AS NewCorp,
dbo.Graduater_Business.CommendNumber
AS CommendNumber,
dbo.Graduater_Business.EmployStatus
AS EmployStatus,
dbo.Graduater_Business.NewCommendTime
AS NewCommendTime,
dbo.Graduater_Business.GetSource
AS GetSource,
dbo.Graduater_Business.EmployTime
AS EmployTime,
dbo.Graduater_Business.Job
AS Job,
dbo.Graduater_Business.FillMan
AS FillMan,
dbo.Graduater_Business.FillTime
AS FillTime,
dbo.Graduater_Business.IsCommendOK
AS IsCommendOK,
dbo.Graduater_Business.ApproveUser
AS ApproveUser,
dbo.Graduater_Business.ApproveTime
AS ApproveTime,
dbo.Graduater_Business.RegistTime
AS RegistTime,
dbo.Graduater_Business.EmployCorp
AS EmployCorp,
dbo.Graduater_Business.JobRemark
AS JobRemark,
CASE WHEN dbo.Graduater_Business.ComeFrom = WS THEN 网上登记
WHEN dbo.Graduater_Business.ComeFrom = HP THEN 华普大厦
WHEN dbo.Graduater_Business.ComeFrom = JD THEN 精典大厦
WHEN dbo.Graduater_Business.ComeFrom = MC THEN 赛马场
WHEN ComeFrom = ZX THEN 高指中心 END AS ComeFromName,
dbo.Person_Contact.Address
AS Address,
dbo.Person_Contact.Zip
AS Zip,
dbo.Person_Contact.Telephone
AS Telephone,
dbo.Person_Contact.Mobile
AS Mobile,
dbo.Person_Contact.Email
AS Email,
dbo.Person_Contact.IM
AS IM,
dbo.Person_Skill.ForeignLanguage
AS ForeignLanguage,
dbo.Person_Skill.ForeignLanguageLevel
AS ForeignLanguageLevel,
dbo.Person_Skill.CantoneseLevel
AS CantoneseLevel,
dbo.Person_Skill.MandarinLevel
AS MandarinLevel,
dbo.Person_Skill.Language
AS Language,
dbo.Person_Skill.TechnicalTitle
AS TechnicalTitle,
dbo.Person_Skill.ComputerLevel
AS ComputerLevel,
dbo.Person_EmployPurpose.JobType
AS JobType,
dbo.Person_EmployPurpose.Vocation
AS Vocation,
dbo.Person_EmployPurpose.JobPlace
AS JobPlace,
dbo.Person_EmployPurpose.Salary
AS Salary,
dbo.Person_EmployPurpose.OnJobDate
AS OnJobDate,
dbo.Person_EmployPurpose.CorpType
AS CorpType,
dbo.Person_EmployPurpose.Job
AS RequireJob,
YEAR(GETDATE()) YEAR(dbo.Person_BasicInfo.Birthday) AS Age,
dbo.Graduater_Business.EmployType
AS EmployType,
dbo.Graduater_Business.EmployTypeCode
AS EmployTypeCode,
dbo.Graduater_Business.EmployCorpType
AS EmployCorpType,
CASE WHEN dbo.Graduater_Business.PrintStatus = 已打印 THEN 已打印
ELSE 未打印 END AS PrintStatus,
dbo.Graduater_Business.PrintTime
AS PrintTime,
CASE WHEN dbo.Graduater_Business.EmployStatus = THEN 已就业
ELSE 未就业 END AS EmployStatusView
FROM dbo.Person_BasicInfo
INNER JOIN dbo.Graduater_Business
ON dbo.Person_BasicInfo.PersonID = dbo.Graduater_Business.PersonID
LEFT OUTER JOIN dbo.Graduater_GraduaterRegist
ON dbo.Graduater_Business.GradBusinessID = dbo.Graduater_GraduaterRegist.GraduaterGUID
INNER JOIN dbo.Person_Contact
ON dbo.Person_BasicInfo.PersonID = dbo.Person_Contact.PersonID
INNER JOIN dbo.Person_Skill
ON dbo.Person_BasicInfo.PersonID = dbo.Person_Skill.PersonID
INNER JOIN dbo.Person_EmployPurpose
ON dbo.Person_BasicInfo.PersonID = dbo.Person_EmployPurpose.PersonID
OPTION (FORCE ORDER)

(5)学习书写专家级的SQL语句

通过上面的步骤,我们已经可以实现自动优化SQL语句,但更重要的是,我们还可以学习如何书写这样高性能的SQL语句。点击界面左方的“Compare Scenarios”按钮,我们可以比较优化方案和原始SQL中的任意2SQL语句,SQL Tuning会将它们之间的不同之处以不同颜色表示出来,
还可以在下方的“执行计划”中,通过比较两条
SQL语句的执行计划的不同,来了解其中的差异(图8)。

8 Compare Scenarios”界面

三、总结

SQL Tuning等人工智能自动SQL优化工具的出现,为我们节省出大量的时间和精力。借助这些工具的帮助,书写专家级的SQL语句将不再是难事。

Quest.Central.For.Databases下载地址:
http://58.251.57.206/down?cid=1669258673&t=14&fmt=&usrinput=Quest.Central&dt=0&ps=0_0&rt=0kbs&plt=0&spd=9

SQL Tuning操作手册英文版:

http://files.cnblogs.com/dreamof/SQL.Tuning.rar

[转载]为您的.NET网站增加OpenID,Window Live,人人网等多种登录方式之一: 增加OpenID登录

mikel阅读(1084)

[转载]为您的.NET网站增加OpenID,Window Live,人人网等多种登录方式之一: 增加OpenID登录 – Otis’s Technology Space – 博客园.

OpenID在国外很流行. 在国内就不怎么样了.. 很多网站,论坛都不支持. 经常在网上逛的人,几乎都要注册很多帐号,记很多密码. 或者是帐号和密码都设定一样.呵. 我在想,如果国内大量的论坛都支持OpenID登录,那么,将会多爽!

不了解OpenID的朋友可 以看中文,或英文http://www.openid.net 的介绍.

本人最近 做的一个网站( http://www.86e0.com ) 有用到OpenID的登录(当然还有其它的登录方式,慢慢会说到). 一开始我也是狂找资料, 中文的,英文的都找过了.可惜的是,资料少得很. 下面总结一些经验和分享一些代码.

.NET下使用OpenID,首先要去下载一个第三方组件:dotnetopenauth. 网址为: http://www.dotnetopenauth.net/

压缩包里会有示例. 由于我的项目是用ASP.NET MVC2,所以我直接看OpenIdRelyingPartyMvc 这个示例. 示例是ASP.NET MVC1.0版的.很快我们就可以找出他的关键代码:
HTML为:

1 <form action="Authenticate?ReturnUrl=<%=HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]) %>" method="post">
2 <label for="openid_identifier">OpenID: </label>
3 <input id="openid_identifier" name="openid_identifier" size="40" />
4 <input type="submit" value="Login" />
5 </form>

Action为:

01 [ValidateInput(false)]
02 public ActionResult Authenticate(string returnUrl) {
03 var response = openid.GetResponse();
04 if (response == null) {
05 // Stage 2: user submitting Identifier
06 Identifier id;
07 if (Identifier.TryParse(Request.Form["openid_identifier"], out id)) {
08 try {
09 return openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
10 } catch (ProtocolException ex) {
11 ViewData["Message"] = ex.Message;
12 return View("Login");
13 }
14 } else {
15 ViewData["Message"] = "Invalid identifier";
16 return View("Login");
17 }
18 } else {
19 // Stage 3: OpenID Provider sending assertion response
20 switch (response.Status) {
21 case AuthenticationStatus.Authenticated:
22 Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
23 FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
24 if (!string.IsNullOrEmpty(returnUrl)) {
25 return Redirect(returnUrl);
26 } else {
27 return RedirectToAction("Index", "Home");
28 }
29 case AuthenticationStatus.Canceled:
30 ViewData["Message"] = "Canceled at provider";
31 return View("Login");
32 case AuthenticationStatus.Failed:
33 ViewData["Message"] = response.Exception.Message;
34 return View("Login");
35 }
36 }
37 return new EmptyResult();
38 }
39 }

最后在HomeController 的Index Action(就是主页)增加 X-XRDS-Location 的Header. Xrds Action是输出上面的Xrds View.如下: 其中请注意xrds的地址. 代码如下.

01 public class HomeController : Controller {
02 public ActionResult Index() {
03 Response.AppendHeader(
04 "X-XRDS-Location",
05 new Uri(Request.Url, Response.ApplyAppPathModifier("~/Home/xrds")).AbsoluteUri);
06 return View("Index");
07 }
08
09 public ActionResult Xrds() {
10 return View("Xrds");
11 }
12 }

XRDS 的View为:

01 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?>
02 <%--
03 This page is a required for relying party discovery per OpenID 2.0.
04 It allows Providers to call back to the relying party site to confirm the
05 identity that it is claiming in the realm and return_to URLs.
06 This page should be pointed to by the 'realm' home page, which in this sample
07 is default.aspx.
08 --%>
09 <xrds:XRDS
10 xmlns:xrds="xri://$xrds"
11 xmlns:openid="http://openid.net/xmlns/1.0"
12 xmlns="xri://$xrd*($v*2.0)">
13 <XRD>
14 <Service priority="1">
15 <Type>http://specs.openid.net/auth/2.0/return_to</Type>
16 <%-- Every page with an OpenID login should be listed here. --%>
17 <%-- We use the Authenticate action instead of Login because Authenticate
18 is the action that receives OpenId assertions. --%>
19 <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/user/authenticate"))%></URI>
20 </Service>
21 </XRD>
22 </xrds:XRDS>

这样就OK啰. 这只是简单的用法. 因为这个只返回很少信息.  一般只有两个,一个是:FriendlyIdentifierForDisplay ,就是用户名,一个是ClaimedIdentifier, 是用户的标识. 如果是这样用就OK,那我这文章也写得没什么意义了.呵. 因为一般我们还要抓到用户的Email,和个性图标.等等一些有用的东西.但是默认的是不返回的.

先看看可以返回什么信息. DotNetOpenAuth中有一个WellKnownAttributes 类, 这个类中定义了一系列可以返回的信息. 下面是这个类的抓图:

image

如何获取这些信息呢? 请看下面的示例代码 :

01 [AcceptVerbs(HttpVerbs.Post)]
02 public ActionResult Login(string openid_identifier)
03 {
04 try
05 {
06 var openid = new OpenIdRelyingParty();
07 IAuthenticationRequest request = openid.CreateRequest(Identifier.Parse(openid_identifier));
08
09
10 var fetch = new FetchRequest();
11 fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
12 fetch.Attributes.AddRequired(WellKnownAttributes.Name.Alias);
13 fetch.Attributes.AddRequired(WellKnownAttributes.Name.FullName);
14 fetch.Attributes.AddRequired(WellKnownAttributes.Media.Images.Default);
15 request.AddExtension(fetch);
16
17
18 /*
19 request.AddExtension(new ClaimsRequest
20 {
21 Email = DemandLevel.Require,
22 FullName = DemandLevel.Require,
23 Nickname = DemandLevel.Require
24 });*/
25 return request.RedirectingResponse.AsActionResult();
26 }
27 catch
28 {
29 ViewData["ErrorMessage"] = "您输入的OpenID 不正确或您的帐号的提供商不提供OpenID服务";
30
31 ViewData["OpenIDLoginURL"] = openid_identifier;
32 return View();
33 }
34 }

这样创建请求就可以成功获取你想要的信息了, 这里是请求获取 Email, 姓名, 个性图标.

注意我注释了的代码, 一开始我也用这样,但是,这个无法获取个性图标.

最后,最后很关键喔.. 配置文件!! 对.. 一开始我因为没注意这个,花了不少时间.. ======

http://www.86e0.com 用的配置文件如下,基本是抄OpenIdRelyingPartyMvc 这个示例的.

01 <dotNetOpenAuth>
02 <openid>
03 <relyingParty>
04 <security requireSsl="false" />
05 <behaviors>
06 <!-- The following OPTIONAL behavior allows RPs to use SREG only, but be compatible
07 with OPs that use Attribute Exchange (in various formats). -->
08 <add type="DotNetOpenAuth.OpenId.Behaviors.AXFetchAsSregTransform, DotNetOpenAuth" />
09 </behaviors>
10 </relyingParty>
11 </openid>
12 <messaging>
13 <untrustedWebRequest>
14 <whitelistHosts>
15 <!-- since this is a sample, and will often be used with localhost -->
16 <add name="localhost" />
17 </whitelistHosts>
18 </untrustedWebRequest>
19 </messaging>
20 <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. -->
21 <reporting enabled="false" />
22 </dotNetOpenAuth>

好了,现在基本没问题了.

剩下就是在登录成功后获取这些信息了. 相关的代码如下:

01 switch (response.Status) {
02 case AuthenticationStatus.Authenticated:
03 string nickName = response.FriendlyIdentifierForDisplay;
04 if (string.IsNullOrEmpty(nickName)) nickName = "匿名用户";
05 string email = string.Empty;
06 string picIcon = string.Empty;
07
08 if (nickName.Length > 50) { nickName = nickName.Substring(0, 50); }
09
10 var claim = response.GetExtension<ClaimsResponse>();
11 var fetch = response.GetExtension<FetchResponse>();
12
13 string picKey = WellKnownAttributes.Media.Images.Default;
14
15 if (fetch !=null && fetch.Attributes != null && fetch.Attributes.Contains(picKey))
16 {
17 var picAttr = fetch.Attributes[picKey];
18 if (picAttr != null && picAttr.Values.Count > 0) { picIcon = picAttr.Values[0]; }
19 }
20 if (claim != null)
21 {
22 nickName = claim.Nickname;
23
24 if (string.IsNullOrEmpty(nickName))
25 {
26 int ttIndex = claim.Email.IndexOf("@");
27 if (ttIndex > 0)
28 {
29 nickName = claim.Email.Substring(0, ttIndex);
30 }
31 else
32 {
33 nickName = claim.Email;
34 }
35 }
36 email = claim.Email;
37 }
38 // 最后授权,入库等.
39 case AuthenticationStatus.Canceled:
40 ViewData["Message"] = "Canceled at provider";
41 return View("Login");
42 case AuthenticationStatus.Failed:
43 ViewData["Message"] = response.Exception.Message;
44 return View("Login");
45 }

OK了. 上面的这么多  if是因为抓出来的资料会有 null的情况.. 这个应该是用户没设定那些资料.

最后,个人博客的话, 不用这么麻烦,比如说老赵的个人博客,直接用https://rpxnow.com/的服务就好了.呵.

感兴趣的朋友欢迎去http://www.86e0.com 体验.

这个系列应该会写三四个. 第二个应该是加入Window live 的登录. 因为Live官方的OpenID登录还在开发中.. 所以不得不用 live sdk 的方式去做.

[转载]ASP.NET MVC 自定义过滤属性实现Enterprise的log功能

mikel阅读(896)

[转载]ASP.NET MVC 自定义过滤属性实现Enterprise的log功能 – 展翅高飞 – 博客园.

现在的企业级开发项目,特别是网站一般都会用到 log功能,想想大部分会用Enterprise Logging Application Block 的功能 或者自己写一个组件,记录系统日志事件,更好的跟踪了解系统运行情况, 现用ASP.NET MVC 的过滤属性实现log功能!

ASP.NET MVC的filter 是一个属性,可以应用到controller 后者action.当Controller或者action method 被调用时,ASP.NET MVC的filter在调用执行前后会被触发。 先看下当Control 里面的action 被调用时的利用继承,自定义类log的效果图:

要实现上面的效果,现自定义一个类LogMessageAttribute,LogMessageAttribute 继承接口IActionFilter ,IResultFilter,也可以选择性 的继承重写类FilterAttribute

IActionFilter interface 定义为:

public interface IActionFilter
{
// Methods
void OnActionExecuted(ActionExecutedContext filterContext);
void OnActionExecuting(ActionExecutingContext filterContext);
}

OnActionExecuting :在Controller 里面的action method 调用之前运行

OnActionExecuted:在Controller 里面的action method 调用之后运行,但是在IResultFilter接口的OnResultExecuting方法执行之前

IResultFilter interface定义为:

public interface IResultFilter
{
// Methods
void OnResultExecuted(ResultExecutedContext filterContext);
void OnResultExecuting(ResultExecutingContext filterContext);
}

OnResultExecuting:在Controller 里面的action method调用处理玩前执行.
OnResultExecuted: 在Controller 里面的action method调用处理玩后执行.

接下来是重头戏:LogMessageAttribute自定义类

代码

[AttributeUsage(AttributeTargets.Class |AttributeTargets.Method ,Inherited=true ,AllowMultiple=true )]
public class LogMessageAttribute:FilterAttribute,IActionFilter,IResultFilter
{
/// <summary>
/// <param name=”LogName “>日志文件路径</para>
/// </summary>
public string LogName { get; set; }

/// <summary>
/// 记录时间,系统版本,当前线程ID 等记录
/// </summary>
/// <param name=”controller”></param>
/// <param name=”action”></param>
/// <param name=”message”></param>
public void LogMessage(string controller, string action, string message)
{
if (!string.IsNullOrEmpty(LogName))
{

TextWriter writer = new StreamWriter(LogName, true);
writer.WriteLine(
################# Begin #################);
writer.WriteLine(
Time:[{0}],DateTime.Now.ToString(yyyy-MM-dd- hh:mm:ss));
writer.WriteLine(
Controller:{0},controller);
writer.WriteLine(
Action:{0},action);
writer.WriteLine(
Message:{0},message);
writer.WriteLine(
Operating System version is:{0},System.Environment.OSVersion.Version.ToString());
writer.WriteLine(
Current Thread ID is:{0},AppDomain.GetCurrentThreadId());
writer.WriteLine(
############### Over ###############);
writer.Close();

}
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
LogMessage(filterContext.RouteData.Values[
controller].ToString(),
filterContext.RouteData.Values[
action].ToString(),
Action exeuting…);
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
LogMessage(filterContext.RouteData.Values[
controller].ToString(),
filterContext.RouteData.Values[
action].ToString(),
Action executed.);
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
LogMessage(filterContext.RouteData.Values[
controller].ToString(),
filterContext.RouteData.Values[
action].ToString(),
Result executing…);
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
LogMessage(filterContext.RouteData.Values[
controller].ToString(),
filterContext.RouteData.Values[
action].ToString(),
Result executed);
}
}

自定义好LogMessageAttribute类,应用到Controller或者action的属性。在Controller 正在执行,或者呈现一个View,一个HTTP请求数据时,就会在日志文件记录一些日志.

在项目的Controller里面应用自定义的属性

代码

[Logging(LogName = @”D:\Project\Project\MVCProject\sky.ExtendMVCFramework\sky.ExtendMVCFramework\Log.log)]
public ActionResult DesplayEmployee()
{
ViewData[
Message] = Our employees welcome you to our site!;
List
<Employee> employees = new List<Employee>
{
new Employee {
FirstName
=sky,
LastName
=yang,
Email
= weflytotti@163.com,
Department
=Development
},
new Employee {
FirstName
=sky,
LastName
=yang,
Email
= weflytotti@163.com,
Department
=Development
}
};
return View(employees);
}

运行程序,正如文章开始所看到的截图!

总结:自定义ASP.NET MVC 的过滤属性实现自己想要的功能只需要继承IActionFilter ,IResultFilter。

[ASP]不能创建对象Scripting.FileSystemObject问题解决办法

mikel阅读(997)

(VBS)ActiveX 部件不能创建对象: Scripting.FileSystemObject

2007-08-25 09:43错误描述:服务器没有启动FSO支持

解决方法:

开启/关闭系统FSO支持方法
windows98系统

在DOS命令行状态输入以下命令:

关闭命令:RegSvr32 /u C:\WINDOWS\SYSTEM\scrrun.dll

打开命令:RegSvr32 C:\WINDOWS\SYSTEM\scrrun.dll

win2000系统:

在CMD命令行状态输入以下命令:

关闭命令:RegSvr32 /u C:\WINNT\SYSTEM32\scrrun.dll

打开命令:RegSvr32 C:\WINNT\SYSTEM32\scrrun.dll

我的设置步骤:IIS中“属性”–目录安全性–匿名访问和验证控制–编辑—匿名访问–编辑–用户名:Administrator–允许IIS控制密码前打勾

win2003
运行regsvr32 scrrun.dll即可。

如果想关闭FSO组件,请运行 regsvr32 /u scrrun.dll即可。