[转载]分享一个Winform下的分页控件

mikel阅读(1317)

[转载]分享一个Winform下的分页控件 – 邀月工作室 – 博客园.

前两天有一个简单的C/S项目用到分页,因为是Winform下,没有现成的,自己也懒得写,就找了下,看到了ycmoon的一个控件

http://www.cnblogs.com/ycmoon/archive/2010/01/07/1640689.html

参考后,做了简化,只保留了分页的部分,主要是点击事件的Delegate,未做过多测试,有兴趣的朋友可以下载源码自行修改,如有好的建议,也可以给我反馈。3w@live.cn,效果如下:

控件设计界面:

邀月工作室

设计时:

邀月工作室

运行时:

邀月工作室

附带一个取分页数据的存储过程:

View Code

Create DataBase Db_TonyPaging go use Db_TonyPaging go if exists (select 1 from sysobjects where id = object_id('DepartDemo') and type = 'U') drop table DepartDemo go /*==============================================================*/ /* Table: DepartDemo */ /*==============================================================*/ create table DepartDemo ( PKID int identity(1,1), DName nvarchar(200) null, DCode nvarchar(500) null, Manager nvarchar(50) null, ParentID int null default 0, AddUser nvarchar(50) null, AddTime datetime null, ModUser nvarchar(50) null, ModTime datetime null, CurState smallint not null default 0, Remark nvarchar(500) null, F1 int not null default 0, F2 nvarchar(300) null, constraint PK_DEPARTDEMO primary key (PKID) ) go truncate table DepartDemo go /***************创建54 条测试数据********************* ****************downmoo 3w@live.cn ***************/ declare @d datetime set @d=getdate() declare @i int set @i=1 while @i<=54 begin --插入一条测试数据 insert into DepartDemo select '国家统计局房产审计'+Cast(@i as Nvarchar(10))+'','0','胡不归',0,'DemoUser',getdate(), '','1900-01-01',1,'专业评估全国房价,为老百姓谋福祉',0,'' set @i=@i+1 end go --***********分页存储过程用于SQL server2005/2008、2008R2**************************** SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO Create PROCEDURE [dbo].[ZJF_CPP_GetPagedRecordFor2005_2008] (@Table varchar(1000), --表名,多表是请使用 tA a inner join tB b On a.AID = b.AID @TIndex nvarchar(100), --主键,可以带表头 a.AID @Column nvarchar(2000) = '*',--读取字段 @Sql nvarchar(3000) = '',--Where条件 @PageIndex int = 1, --开始页码 @PageSize int = 10, --页大小 @Sort nvarchar(200) = '' --排序字段 ) AS DECLARE @strWhere varchar(2000) declare @strsql nvarchar(3900) IF @Sql IS NOT NULL AND len(ltrim(rtrim(@Sql)))>0 BEGIN SET @strWhere = ' WHERE ' + @Sql + ' ' END ELSE BEGIN SET @strWhere = '' END if (charindex(ltrim(rtrim(@TIndex)),@Sort)=0) begin if(@Sort='') set @Sort = @TIndex + ' DESC ' else set @Sort = @Sort+ ' , '+@TIndex + ' DESC ' end IF @PageIndex < 1 SET @PageIndex = 1 if @PageIndex = 1 --第一页提高性能 begin set @strsql = 'select top ' + str(@PageSize) +' '+@Column+ ' from ' + @Table + ' ' + @strWhere + ' ORDER BY '+ @Sort end else begin /**//**//**//*Execute dynamic query*/ DECLARE @START_ID nvarchar(50) DECLARE @END_ID nvarchar(50) SET @START_ID = convert(nvarchar(50),(@PageIndex - 1) * @PageSize + 1) SET @END_ID = convert(nvarchar(50),@PageIndex * @PageSize) set @strsql = ' SELECT '+@Column+ ' FROM (SELECT ROW_NUMBER() OVER(ORDER BY '+@Sort+') AS rownum, '+@Column+ ' FROM '+@Table +' WITH(NOLOCK) ' + @strWhere +') AS D WHERE rownum BETWEEN '+@START_ID+' AND ' +@END_ID +' ORDER BY '+@Sort END EXEC(@strsql) print @strsql set @strsql = 'SELECT Count(1) as TotalRecords FROM ' + @Table +' WITH(NOLOCK) ' + @strWhere print @strsql EXEC(@strsql)

在WinForm项目中,需要设置控件的总记录数RecordCount(由分页存储过程计算得出),和翻页事件winFormPager1_PageIndexChanged

邀月工作室
邀月工作室

邀月工作室

测试源码如下:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; namespace DemoPager { public partial class frmMain : Form { public frmMain() { InitializeComponent(); } #region Members //总记录数 public int RecordCount = 0; private string strConn = @"Data Source=ap2\vegnet;Initial Catalog=Db_TonyPaging;Integrated Security=SSPI;"; //"Server=localhost;database=Db_TonyPaging;uid=sa;pwd=sa;"; private string strProcedure = "ZJF_CPP_GetPagedRecordFor2005_2008"; #endregion #region Methods /// <summary> /// 绑定第Index页的数据 /// </summary> /// <param name="Index"></param> private void BindDataWithPage(int Index) { winFormPager1.PageIndex = Index; //winFormPager1.PageSize = 10;; ; dgvList.DataSource = GetData(strConn, strProcedure, Index, winFormPager1.PageSize); //获取并设置总记录数 winFormPager1.RecordCount = RecordCount; } /// <summary> /// 获取数据源 /// </summary> /// <param name="conn"></param> /// <param name="strProcedure"></param> /// <param name="pageIndex"></param> /// <param name="pageSize"></param> /// <returns></returns> private DataTable GetData(string conn, string strProcedure, int pageIndex, int pageSize) { using (SqlConnection connection = new SqlConnection(conn)) { SqlCommand command = new SqlCommand(strProcedure, connection); command.CommandType = CommandType.StoredProcedure;//采用存储过程 //存储过程参数 command.Parameters.Add("@Table", SqlDbType.NVarChar, 1000).Value = "DepartDemo"; command.Parameters.Add("@TIndex", SqlDbType.NVarChar, 100).Value = "PKID"; command.Parameters.Add("@Column", SqlDbType.NVarChar, 2000).Value = "*"; command.Parameters.Add("@Sql", SqlDbType.NVarChar, 3000).Value = " 1=1 "; command.Parameters.Add("@PageIndex", SqlDbType.Int, 8).Value = pageIndex.ToString(); command.Parameters.Add("@PageSize", SqlDbType.Int, 8).Value = pageSize.ToString(); command.Parameters.Add("@Sort", SqlDbType.NVarChar, 200).Value = " PKID desc"; //打开连接 if (connection.State != ConnectionState.Open) { connection.Open(); } try { //填充数据 SqlDataAdapter da = new SqlDataAdapter(command); DataSet ds = new DataSet(); da.Fill(ds); //获取总记录数 RecordCount = Convert.ToInt32(ds.Tables[1].Rows[0][0]); //返回数据集 return ds.Tables[0]; } catch (SqlException err) { MessageBox.Show(err.Message); return null; ; } finally { connection.Close(); } } } #endregion #region Events private void frmMain_Load(object sender, EventArgs e) { //不自动生成列 dgvList.AutoGenerateColumns = false; //绑定数据 BindDataWithPage(1); } /// <summary> /// 翻页事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void winFormPager1_PageIndexChanged(object sender, EventArgs e) { BindDataWithPage(winFormPager1.PageIndex); } #endregion } }

下载控件源码及演示程序(含SQL)

下载地址一

下载地址二

邀月注:本文版权由邀月和博客园共同所有,转载请注明出处。
助人等于自助!   3w@live.cn

[转载]八款开源Android游戏引擎

mikel阅读(1191)

[转载]八款开源Android游戏引擎 – 语虫 – 博客园.

很 多初学Android游戏开发的朋友,往往会显得有些无所适从,他们常常不知道该从何处入手,每当遇到自己无法解决的难题时,又往往会一边羡慕于 iPhone下有诸如Cocos2d-iphone之类的免费游戏引擎可供使用,一边自暴自弃的抱怨Android平台游戏开发难度太高,又连个像样的游 戏引擎也没有,甚至误以为使用Java语言开发游戏是一件费力不讨好且没有出路的事情。

事实上,这种想法完全是没有必要且不符合实际的,作为能和苹果iOS分庭抗礼的Android(各种意义上),当然也会有相当数量的游戏引擎存在。仅仅因为我们处于这个狭小的天地间,与外界接触不够,所以对它们的存在茫然不知罢了。

下面我就罗列出八款常见的Android游戏引擎,以供有需要者参考(收费,下载量过小,不公布源码,以及鄙人不知道(-_-)的引擎不在此列)。

1、Angle


Angle是一款专为Android平台设计的,敏捷且适合快速开发的2D游戏引擎,基于OpenGL ES技术开发。该引擎全部用Java代码编写,并且可以根据自己的需要替换里面的实现,缺陷在于文档不足,而且下载的代码中仅仅包含有少量的示例教程。

最低运行环境要求不详。

项目地址:http://code.google.com/p/angle/

2、Rokon


rokon 是一款Android 2D游戏引擎,基于OpenGL ES技术开发,物理引擎为Box2D,因此能够实现一些较为复杂的物理效果,该项目最新版本为 2.0.3 (09/07/10)。总体来说,此引擎最大的优点在于其开发文档相当之完备,并且项目作者对反馈Bug的修正非常之神速,所以该框架的使用在目前也最为 广泛,有人干脆将它称为Cocos2d-iPhone引擎的Android版(业务逻辑和编码风格上也确实很像)。附带一提,国内某个需要注册会员才能下 载的Android游戏框架衍生于此框架,所以大家也不要刻板的认为收费便一定是好的,免费就一定不好。

最低运行环境要求为Android 1.5。

项目地址:http://code.google.com/p/rokon/

3、LGame


LGame 是一款国人开发的Java游戏引擎,有Android及PC(J2SE)两个开发版本,目前最高版本同为0.2.6(31/07/10)。其底 层绘图器LGrpaphics封装有J2SE以及J2ME提供的全部Graphics API(PC版采用Graphics2D封装,Android版采用Canvas模拟实现),所以能够将J2SE或J2ME开发经验直接套用其中,两版本 间主要代码能够相互移植。Android版内置有Admob接口,可以不必配置XML直接硬编码Admob广告信息。

该 引擎除了基本的音效、图形、物理、精灵等常用组件以外,也内置有Ioc、xml、http等常用Java组件的封装,代价是jar体积较为庞大,PC版 已突破1.2MB,Android版有所简化也在500KB左右。此外,该引擎还内置有按照1:1实现的J2ME精灵类及相关组件,可以将绝大多数 J2ME游戏平移到Android或PC版中。唯一遗憾的是,该项目作者是个极其懒惰的家伙,开发文档从去年说到今年依旧没有提供,只有游戏示例可供下 载。

最低运行环境要求为Android 1.1。

项目地址:http://code.google.com/p/loon-simple/

4、AndEngine


andengine同样是一款基于OpenGL ES技术的Android游戏引擎,物理引擎同样为Box2D(标配|||)。该框架性能普通,文档缺乏,但示例较为丰富。

下载地址(未直接提供jar下载,源码可通过svn提取):http://code.google.com/p/andengine/

最低运行环境要求不详。

项目地址:http://code.google.com/p/rokon/

5、libgdx


libgdx 是一款基于OpenGL ES技术开发的Android游戏引擎,支持Android平台下的2D游戏开发,物理引擎采用Box2D实现。单就性能角度来说,堪称是一款非常强大的 Android游戏引擎,但缺陷在于精灵类等相关组件在使用上不够简化,而且文档也较为匮乏。

最低运行环境要求不详。

项目地址:http://code.google.com/p/libgdx/

6、jPCT


jPCT 是一款基于OpenGL技术开发的3D图形引擎(PC环境为标准OpenGL,Android为OpenGL ES), 以Java语言为基础的,拥有功能强大的Java 3D解决方案。该引擎与LGame(此为2D游戏引擎)相类似,目前拥有PC(J2SE)以及Android两个开发版本。

jPCT 的最大优势之一,就在于它惊人的向下兼容性。在PC环境中,jPCT甚至可以运行在JVM1.1环境之中,因为jPCT内部提供的图形渲染接口完 全符合所有的Java 1.1规范(就连已经消失的Microsoft VM乃至更古老的Netscape 4 VM也不例外)。

最低运行环境要求为Android 1.5。

项目地址:http://www.jpct.net/jpct-ae/

7、Alien3d 

Alien3d 是一款体积非常之小的Android 3D游戏引擎,基于OpenGL ES技术开发。为了压缩体积,它根据不同功能采用多jar方式发布(包括alien3d-engine.jar,alien3d- tiled.jar,alien3d-sprites.jar,alien3d-shapes.jar,alien3d- particles2d.jar,),事实上它的核心文件大约只有40KB,所有相关jar的总和也不足150KB。

最低运行环境要求为Android 1.5。

项目地址:http://code.google.com/p/alien3d/

8、Catcake


Catcake是一款跨平台的Java 3D图形引擎,目前支持PC(J2SE)及Android环境运行(已有iPhone版规划)。该引擎在易用性和运行性能上皆有出色的表现,支持常见的游戏开发功能,诸如精灵动画,音频处理和视频播放等。

最低运行环境要求为Android 1.6。

项目地址:http://code.google.com/p/catcake/

[转载]教你30秒打造强类型ASP.NET数据绑定

mikel阅读(966)

[转载]教你30秒打造强类型ASP.NET数据绑定 – 爵士甜菜 – 博客园.

更新:感谢Dacey 韦恩卑鄙 dudu老大等人的建议我已添加了扩展方法版本。喜欢扩展方法这种空降兵的感觉 🙂

数据绑定似乎是ASP.NET老掉牙的东西了。可是你知道吗,只需要一点小小的改动就可以替换Eval,摆脱字符串依赖并且大大提高性能。

首先在code behind中加入以下方法

protected virtual object ExpHelper<TEntity, TREsult>(Func<TEntity, TREsult> func) { var itm = GetDataItem(); return func((TEntity)itm); }

这段代码就是最核心的秘诀了,你完全可以忽视它到底在做什么。其实就是截获每一个被绑定的数据项,并进行强类型转换。

假设我们定义了学生类

public class Student { public string Name { get; set; } public int Age { get; set; } }

如果希望在页面中使用强类型访问学生类而不是用Eval,定义专门访问学生的方法

protected object Stu<TResult>(Func<Student, TResult> func) { return ExpHelper<Student, TResult>(func); }

大功告成,于是在页面里我们就能这样绑定数据了

<ul> <asp:Repeater ID="rptStudents" runat="server"> <ItemTemplate> <li><%#Stu(_=>_.Name + "(" +_.Age+")")%></li> </ItemTemplate> </asp:Repeater> </ul>

这样做有四大优势

  1. 得到编译时检测
  2. 享受智能提示
  3. 强类型转换比Eval反射性能更高
  4. 页面中的表示更丰富,如上我们可以自由拼接想要的字符串,非常像MVC

更神奇的是可以支持多层嵌套哦。比如我们定义学生的集合Group类和访问器,然后就能用嵌套的Repeater显示分组信息了。完整程序如下

<%@ Page Language="C#" AutoEventWireup="true"%> <script runat="server"> public class Student { public string Name { get; set; } public int Age { get; set; } } public class Group { public IEnumerable<Student> Students { get; set; } } protected void Page_Load(object sender, EventArgs e) { //一群学生 var students = new[] { new Student{Name="mike",Age=23}, new Student{Name="jane", Age=12}, new Student{Name="frank",Age=25}, new Student{Name="susan",Age=32}, }; rptStudents.DataSource = students; //分两组 var group0 = new Group(); group0.Students = students.Take(2); var group1 = new Group(); group1.Students = students.Skip(2).Take(2); rptGroups.DataSource = new[] { group0, group1 }; DataBind(); } protected virtual object ExpHelper<TEntity, TREsult>(Func<TEntity, TREsult> func) { var itm = GetDataItem(); return func((TEntity)itm); } //Student访问器 protected object Stu<TResult>(Func<Student, TResult> func) { return ExpHelper<Student, TResult>(func); } //Group访问器 protected object Grp<TResult>(Func<Group, TResult> func) { return ExpHelper<Group, TResult>(func); } </script> <!DOCTYPE html> <html> <body> <%--单层--%> <ul> <asp:Repeater ID="rptStudents" runat="server"> <ItemTemplate> <li><%#Stu(_=>_.Name + "(" +_.Age+")")%></li> </ItemTemplate> </asp:Repeater> </ul> <%--嵌套--%> <ul> <asp:Repeater ID="rptGroups" runat="server"> <ItemTemplate> <li> <ol> <asp:Repeater ID="Repeater1" runat="server" DataSource='<%#Grp(_=>_.Students) %>'> <ItemTemplate> <li><%#Stu(_=>_.Name + "(" +_.Age+")")%></li> </ItemTemplate> </asp:Repeater> </ol> </li> </ItemTemplate> </asp:Repeater> </ul> </body> </html>

PS

本文是我以前写的没有发表的小发明,现在拿出来晒,主要是因为这个方法好像知道的人很少。希望大家能帮助测试一下性能,如果觉得合适大可以运用到实际工作中。

更新:

感谢Dacey 韦恩卑鄙 dudu老大等人的建议
我已添加了扩展方法版本。喜欢扩展方法这种空降兵的感觉。

现在只要添加一个static的帮助类,名字随你喜欢

public static class Helper { static object ExpHelper<TEntity, TResult>(Page page, Func<TEntity, TResult> func) { var itm = page.GetDataItem(); return func((TEntity)itm); } public static object Eval<T>(this Page page, Func<T, object> func) { return ExpHelper<T, object>(page, func); } }

在页面中就可以

<%#this.Eval<Student>(_ => _.Name + "(" + _.Age + ")")%>
  • 注意this是必须的
  • 扩展方法具有很好的粘合性
  • 不需要一个父类定义通用方法
  • 泛型提供多个副本并且容易看清类型
  • 另外能很好的支持refactor,大家试试用ctrl+r+r改属性名

[转载]Web字体格式介绍及浏览器兼容性一览

mikel阅读(1058)

[转载]Web字体格式介绍及浏览器兼容性一览 – 梦想天空 – 博客园.

目前,文字信息仍是网站最主要的内容,随着CSS3技术的不断成熟,Web字体逐渐成为话题,这项让未来Web更加丰富多彩的技术拥有多种实现 方案,其中之一是通过@font-face属性在网页中嵌入自定义字体,主流的浏览器都支持这项技术,具体实现例子将在下一篇文章介绍,本文介绍主要的几 种Web字体格式及各浏览器兼容情况。

Web字体格式介绍

TrueType (.ttf)

Windows和Mac系统最常用的字体格式,其最大的特点就是它是由一种数学模式来进行定义的基于轮廓技术的字体,这使得它们比基于矢量的字体更容易处理,保证了屏幕与打印输出的一致性。同时,这类字体和矢量字体一样可以随意缩放、旋转而不必担心会出现锯齿。

EOT – Embedded Open Type (.eot)

嵌入字体格式(EOT)是微软开发的一种技术,允许 OpenType 字体嵌入到网页并可以下载至浏览器渲染,浏览器根据 CSS 中 @font-face 的定义,下载,渲染这种 .EOT 后缀的字体文件。这些文件只在当前页活动的状态下,临时安装在用户的系统中。

OpenType (.otf)

OpenType是一种可缩放字型(scalable font)电脑字体类型,采用PostScript格式,是美国微软公司与Adobe公司联合开发,用来替代TrueType字型的新字型。这类字体的文 件扩展名为.otf,类型代码是OTTO,现行标准为OpenType 1.4。OpenType最初发表于1996年,并在2000年之后出现大量字体。它源于微软公司的TrueType Open字型,TrueType Open字型又源于TrueType字型。OpenType font包括了Adobe CID-Keyed font技术。Adobe公司已经在2002年末将其字体库全部改用OpenType格式。

WOFF – Web Open Font Format (.woff)

相对于 TrueType 和 OpenType ,WOFF(Web开发字体格式)是一种专门为了 Web 而设计的字体格式标准,它并不复杂,实际上只是对于 TrueType / OpenType 等字体格式的封装,并针对网络使用加以优化:每个字体文件中含有字体以及针对字体的元数据(Metadata),字体文件被压缩,以便于网络传输,并且不 包含任何加密或者 DRM 措施。包括 Adobe、 Lino Type、Monotype 在内的几乎所有主要的字体供应商都加入到支持 WOFF 的行列中来

SVG (Scalable Vector Graphics) Fonts (.svg)

顾名思义,就是使用SVG技术来呈现字体,还有一种gzip压缩格式的SVG字体.svgz。SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式。SVG由W3C制定,是一个开放标准。SVG严格遵从XML语 法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。SVG可以使你设计的网页可以更加精彩细致,使用简单的文本命 令,SVG可实现色彩线性变化、路径、自定义字体、透明效果、滤镜效果等各式常见的图形图像效果。

字体格式转换工具

EOTFast

这个工具我刚用过,非常好用的一个工具,用于把TTF文件转为EOT格式。

Microsoft WEFT

微软提供的字体格式转换工具。

ttf2eot

可以转换TTF文件为EOT格式。
ttf2eot Command Line Utility

另外推荐几个在线的转换工具:

如果想把OTF文件转为TTF格式,可以使用FontForge来转换。

浏览器兼容性一览

使用CSS3的@font-face属性可以实现在网页中嵌入任意字体(其实IE4就支持这个属性了,后来这个属性加入到了CSS3中),但是 IE只支持微软自有的EOT格式字体,而其他浏览器都不支持这一字体格式,其它浏览器可以设置TTF(TrueType)和OTF(OpenType)两 种字体作为自定义字体,浏览器对@font-face属性及各种字体格式支持详的细情况如下:

Browser @font-face TrueType WOFF EOT SVG SVGZ
4+ 9+ 9+ 4+
3.5+ 3.5+ 3.6+
4+ 4+ 6+ 4+ 6+
3.1+ 3.1+ 6+ 3.1+ 3.1+
10+ 10+ 11.1+ 10+ 10+

(来源:梦想天空 原文:Web字体格式介绍及浏览器兼容性一览

[转载]构建高性能ASP.NET站点 第五章—性能调优综述(中篇)

mikel阅读(860)

[转载]构建高性能ASP.NET站点 第五章—性能调优综述(中篇) – ASP.NET 架构 – 博客园.

利用分析工具分析加载页面信息

站点的优化说到底还是站点每一个页面的优化,即使得站点的页面更快的呈现在用户的眼前。所以在此之前,我们首先来看看一个web页面的组成部分:

1. Html文件:ASP.NET中,Html文件通常是通过解析.aspx页面而产生的。而这个解析过程在服务端进行,同时这个过程也消耗了服务端的大部分资源。

2. 图片和flash文件:一个站点往往包含很多这样的的文件。

3. Jscss文件:这些文件可以阻止页面的呈现。

清楚了页面的组成部分之后,我们可以把使得页面加载变慢的因素分为如下几类:

1. 服务端的花费大量时间解析.aspx,也就是说服务端产生html文本的时间过长(导致这个问题的原因很多,例如数据库查询很慢,影响了页面的生成)。

2. 在服务端和浏览器之间,传递html文本花费大量的时间(例如,页面中的Viewstate很大,网络很慢等)。

3. 图片和flash文件的加载花费大量的时间。

4. Jscss的加载花费大量的时间。

为了使得一个页面的加载变快,那么我们就得知道:是以上哪一个过程影响了速度(本系列的后续文章会详细讲述)。一旦知道了是那类问题导致了性能问题,那么我们就可以对症下药。

下面我们就通过一些工具来简单的查看和分析站点的性能,目的让大家快速的了解如何进行简单的性能分析。

我们用瀑布图来分析页面的每个组成部分加载所花的时间,例如下面就是博客园首页加载的分析图(部分的截图)。

我们可以通过图中的“时间线“长短来知道每个文件加载的时间。时间线长越长,那么加载该文件的时间越长,反之。

看完了上面的图之后,大家应该很想知道:上面的图是如何生成的,那么下面就介绍一些生成页面加载瀑布图的工具。

我们首先来看看:Firefox+Firebug

Firefox下载地址:http://www.mozilla.com/en-US/firefox/

Firebug下载地址:http://getfirebug.com/

下面就开始演示如何生成页面加载的瀑布图(如果熟悉这个流程的朋友可以跳过此段)

1. 打开Firefox,然后按下F12,就看到如下的画面:

2. Firebug中,在选择“网络”下拉框中选择“启用”。

OK,下面我们就来详细的看看在瀑布图中一些数据和图示的意义。

1. 请求和响应的相关信息

在瀑布图中,点击每一行的”+”如下:

符号展开之后,我们可以看到所有的请求和响应头,如下:

2. 时间线的相关信息

当我们把鼠标移到着色的时间线bar上面的时候,我们就可以看到请求该文件所花的时间的详细信息,如下:

我们用一个表格来讲述每个时间段的含义:

域名解析 寻找请求的文件所在的服务器的IP地址所花的时间
建立连接 打开客户端到服务端的TCP链接所花的时间
发送请求 浏览器发送请求所花的时间。大家可能有点奇怪:为什么发送请求还要等待,难道不是打开连接就发送了请求吗?

其实浏览器会把要请求的文件的请求放在请求队列中,队列的长度一般都是有限制的,如果页面需要请求的文件很多,如果队列达到了最大的限制数量,那么后续的文件请求会等待。

等待响应 客户端发送请求一直到接受服务端的第一个字节所花的时间
接受数据 接受整个请求文件或者数据所花的时间
‘DOMContentLoaded’ 事件 从该请求开始进行DNS寻址到整个页面的DOM被下载下来所花的时间。注意:此时只是页面的骨架被下载下来了,其中的一些资源(如果图片,js等)没有下载下来。当页面的DOM下载下来了之后,用户就可以看到了页面了,但是有些资源还在陆续的下载中。
‘load’ 事件 从该请求开始进行DNS寻址到整个页面全部(包括资源)下载下来所花的时间。

3. 页面级的请求信息

也就是整个页面的请求的一些汇总信息。

OK,今天就基本讲述这些,下一篇就开始讲述利用分析工具分析性能瓶颈,用上面的瀑布图来分析一些常见的性能问题,这些性能问题会在后续文章中一个个的给出解决方案,敬请关注! :)

[转载]一套内容采集系统 解放编辑人员

mikel阅读(1185)

[转载]一套内容采集系统 解放编辑人员 – 葡萄城控件技术团队博客 – 博客园.

内容采集系统,对于以内容为主的网站来说是非常好的助手,除了原创内容外,其它内容需要 编辑人员或者采集系统来收集整理,然后添加到自己的网站里。Discuz DvBBS CMS等产品,内部都自带了一个内容采集功能,来采集指定的相关内容。 单客户端的火车头采集器也可以非常好的采集指定的内容。这些工具都是想让机器代替人工,把编辑人员从内容搬运的工作中解放出来,做一些更高端的工作,例如 采集结果的内容微调,SEO优化,设定精确的采集规则,让采集的内容更加符合自己网站的需要。
下面的内容采集系统就是从这个想法开发而来的,这个采集系统由两个部分组成:
1.  编辑人员所使用的采集规则设定器和对采集结果进行审核、微调和发布所使用的Web站点。
2.  部署在服务器上的定时采集器和定时发送器。
首先由编辑人员通过一个采集规则设定器(NiceCollectoer.exe)设定要采集的站点,再等采集完成后,编辑人员再通过 一个Web站点(PickWeb)对采集的结果进行审核、微调和优化然后发布到自己的网站上。编辑人员所需要做的是采集规则的设定,和对采集结果的优化, 其它部分的工作都由机器完成。
1
NicePicker 是Html 分析器,用来抽取Url,NiceCollector 和HostCollector 都使用NicePicker来分析Html, NiceCollectoer 就是采集规则设定器,一个目标网站只用设定一次:
2

3
使用起来和最早的火车头采集器类似,这里使用博客园来做目标采集站点, 设定采集精华区的文章,采集规则非常简单:当编辑人员设定好采集规则后,这些规则会保存到NiceCollector.exe同目录下的 Setting.mdb中。一般当采集规则设定好以后,基本上不用再变动了,只在目标网站的Html Dom结构发生变化时,需要再次微调一下采集规则。NiceCollector同时用于新目标采集站点的设定和添加操作。
等编辑人员完成采集规则的设定后,把Setting.mdb放到 HostCollector.exe下, HostCollector 会根据Setting.mdb的设定进行真正的采集,并把采集的结果存入数据库。
到这一步就完成了内容的采集工作,编辑人员可以打开PickWeb,对采集结果进行微调和优化,然后审核通过并发送到自己的网站上:
4
5
真 正发送采集结果到自己网站的工作不是由PickWeb完成的,编辑人员完成内容审核后,PostToForum.exe 会读取数据库并发送这条通过审核的采集结果到自己的网站上,在自己的网站上当然需要一个. ashx或者某种其它方式来接收采集的结果,不建议PostToFormu.exe直接去操作自己网站的数据库,最好通过自己网站上的某个API,来接收 采集结果。
NiceCollectoer, HostCollector, PickWeb, PostToForum, 这几个程序联合工作,基本上已经完成了采集和发送的工作,HostCollector, PickWeb, PostToForum 是部署在服务器上的,HostCollector需要被周期性的调用,来采集目标网站所产生的新内容,HostRunnerService.exe 是一个Windows Service,用来周期性调用HostCollector,使用管理员身份在控制台下运行 installutil / i HostRunnerService.exe 就可以安装这个Windows Service了:
6
HostRunnerService 的配置也很简单:
7
在RunTime.txt 中设定每天定时采集几次:
8
当 新内容被采集后,编辑人员需要定期的登录PickWeb,来优化、微调、并审核新内容,也可以设定默认审核通过。同样PostToForum 也需要被周期性的调用,用来发送审核通过的新内容,CallSenderService.exe 与 HostRunnerService.exe类似,也是一个Windows Service,用来定期的调用PostToFormu.exe。
到这里整个系统基本上完成了,除此之外还有两个小东东: SelfChecker.exe 和HealthChecker.exe。 SelfCheck.exe 是用来检查Setting.mdb中设定的规则是否是一个有效的规则,例如检查采集规则是否设定了内容采集项。HealthChecker.exe用来收 集HostCollector.exe 和 PostToForum.exe 所产生的log,然后将log发送给指定的系统维护人员。
这个内容采集系统还有很多地方需要改进和优化,现在的状态只能说是个Prototype吧,例如 NicePick 需要进一步抽象和重构,给出更多的Interface,把分析Html的各个环节插件化,在各个分析步骤上,可以让用户加载自己的分析器。 在NiceCollector上,需要更多更全面的采集规则设定。在PickWeb上可以加入一些默认的SEO优化规则,如批量SEO优化Title的内 容,等其它方面吧。

可执行文件下载:

08_453455_if8l_NROutput.rar

源代码下载:

08_234324_if8l_NiceCollector.rar

[转载]如何将XML与OBJECT进行相互转换(泛型以及通用方法)

mikel阅读(1053)

[转载]如何将XML与OBJECT进行相互转换(泛型以及通用方法) – JasenKin – 博客园.

过年的这段时间一直没有闲着,总体来说可以分为以下2个部分的学习。

1:ORMCodeHelper的参考与学习。

2:MVC3的学习。

对于ORMCodeHelper(Keny的),完全的采用插件式开发,即插即用,个人感觉还是比较爽的,架构不错。它包括了SQL SERVER 2000,SQL SERVER 2005以及ORACLE的相关C#代码的生成。比哥一年前写的那个牛多了,哈哈,哥去年乱写了个网页版的(http://www.cnblogs.com/jasenkin/archive/2010/02/11/1667511.html), 现在看一年前的代码,哥感叹,这个谁写的代码,TMD实在写的太烂了!!!当然,ORMCodeHelper与CodeSmith相比,还是有差距的哦。 霖哥以前给我的codesmith模板(N层的),哥一直没时间仔细看,哥知道那个模板可以把所有的代码全部生成,其中包括N层代码、存储过程、页面等 等。虽然时间就像乳沟,只要挤一挤总还是有的!但是,哥真的……本来9号哥都是请假休息的,唉,又要哥上班了….

还有就是对于MVC3,Razor实在太给力了,扔掉MVC2吧,哈哈,@确实挺不错的。

在ORMCodeHelper中,对于配置文件的使用的思路还是不错的,哥学以致用,提炼个泛型的出来(其实最主要的还是插件开发的架构)。对于 XML与OBJECT的转换来说,下面讲的是一种Serialize方法。其实哥还有另外一种通过反射将XML转换成对象的方法,不过,涉及到公 司****,那种方法还是不写了。当然,那种方法哥是可以横着写了(因为哥早就背在心里了),哈哈,通用的代码….

先看代码,如下:

public static class Serializer
{

public static void Serialize<T>(string filePath, T[] array)  where T:new()
{
if (string.IsNullOrEmpty(filePath)||
array == null||array.Length==0)
{
return;
}

try
{
XmlSerializerFactory xmlSerializerFactory = new XmlSerializerFactory();
XmlSerializer xmlSerializer =
xmlSerializerFactory.CreateSerializer(array.GetType(), typeof(T).Name);
Stream stream = new FileStream(filePath, FileMode.Create);
xmlSerializer.Serialize(stream, array);
stream.Close();
}
catch
{
}
}

public static void Serialize(string filePath, object obj)
{
if (string.IsNullOrEmpty(filePath) || obj == null)
{
return;
}

try
{
XmlSerializerFactory xmlSerializerFactory = new XmlSerializerFactory();
XmlSerializer xmlSerializer =
xmlSerializerFactory.CreateSerializer(obj.GetType(), obj.GetType().Name);
Stream stream = new FileStream(filePath, FileMode.Create);
xmlSerializer.Serialize(stream, obj);
stream.Close();
}
catch
{
}
}

}

public static List<T> Deserialize<T>(string filePath)  where T:new()
{
List<T> results=new List<T>();
if (string.IsNullOrEmpty(filePath)||!File.Exists(filePath))
{
return results;
}object obj = null;
try
{
XmlSerializerFactory xmlSerializerFactory = new XmlSerializerFactory();
XmlSerializer xmlSerializer =
xmlSerializerFactory.CreateSerializer(typeof(T[]), typeof(T).Name);
Stream stream = new FileStream(filePath, System.IO.FileMode.Open);
obj = xmlSerializer.Deserialize(stream);
stream.Close();

results.AddRange(obj as T[]);
}
catch
{
}

return results;
}

public static object Deserialize(string filePath, Type targetType)
{
if (string.IsNullOrEmpty(filePath)||!File.Exists(filePath)
|| targetType == null)
{
return null;
}

object obj = null;
try
{
XmlSerializerFactory xmlSerializerFactory = new XmlSerializerFactory();
XmlSerializer xmlSerializer =
xmlSerializerFactory.CreateSerializer(targetType, targetType.Name);
Stream stream = new FileStream(filePath, FileMode.Open);
obj = xmlSerializer.Deserialize(stream);
stream.Close();
}
catch
{
}

return obj;
}

从上面4个方法,可以看出主要是通过XmlSerializer将对象序列化为XML以及将XML反序列化为对象,这种方法比较简单,而且易用。

(一)Serialize<T>(string filePath, T[] array),Deserialize<T>(string filePath)

通过单元测试来看看Serialize<T>(string filePath, T[] array)方法生成的XML内容,先注释掉//DeleteFile(filePath);

public void SerializeTestHelper(AppSetting[] inputs)
{
AppSetting[] settings = inputs;
string filePath = @”d:\” + typeof(AppSetting).Name + “.config”;

Serializer.Serialize<AppSetting>(filePath, settings);
List<AppSetting> results = Serializer.Deserialize<AppSetting>(filePath);

int length = results.Count;
Assert.IsTrue(length == settings.Length);

for (int index = 0; index < length; index++)
{
Assert.IsTrue(results[index].Value == settings[index].Value);
Assert.IsTrue(results[index].Key == settings[index].Key);
Assert.IsTrue(results[index].Author == settings[index].Author);
}

//DeleteFile(filePath);
}

生成的XML如下:

<?xml version=”1.0″?>
<ArrayOfAppSetting xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”AppSetting”>
<AppSetting>
<Key>key0</Key>
<Value>value0</Value>
<Author>author0</Author>
</AppSetting>
<AppSetting>
<Key>key1</Key>
<Value>value1</Value>
<Author>author1</Author>
</AppSetting>
<AppSetting>
<Key>key2</Key>
<Value>value2</Value>
<Author>author2</Author>
</AppSetting>
</ArrayOfAppSetting>

从上面的单元测试可以看出:通过Serialize<T>(string filePath, T[] array)方法将对象数组生成XML内容,可以通过Deserialize<T>(string filePath)将XML内容转换成相应的对象数组,内容相一致。

(二)Serialize(string filePath, object obj),Deserialize(string filePath, Type targetType)
通过单元测试来看看Serialize(string filePath, object obj)方法生成的XML内容,先注释掉//DeleteFile(filePath);

private static void SerializeTestHelper()
{
AppSetting setting = new AppSetting()
{
Author = “AuthorTest”,
Key = “KeyTest”,
Value = “ValueTest”
};
string filePath = @”d:\” + typeof(AppSetting).Name + “.config”;

Serializer.Serialize(filePath, setting);
AppSetting result = Serializer.Deserialize(filePath, typeof(AppSetting)) as AppSetting;

Assert.IsTrue(result.Value == setting.Value);
Assert.IsTrue(result.Author == setting.Author);
Assert.IsTrue(result.Key == setting.Key);

//DeleteFile(filePath);
}

生成的XML如下:

<?xml version=”1.0″?>
<AppSetting xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”AppSetting”>
<Key>KeyTest</Key>
<Value>ValueTest</Value>
<Author>AuthorTest</Author>
</AppSetting>

从上面的单元测试可以看出:通过Serialize(string filePath, object obj)方法将对象生成XML内容,可以通过Deserialize(string filePath, Type targetType)将XML内容转换成相应的对象,内容相一致。其中,object也可以是对象数组的,这个留给读者自己去验证。

测试都是可以通过的,这里仅仅是验证正确的功能,如下图:

源代码(VS2008)下载:Jasen.SerializationApp.rar

[转载]ASP.NET MVC随想

mikel阅读(884)

[转载]ASP.NET MVC随想 – 快乐的博客 – 博客园.

ASP.NET Web Form到ASP.NET MVC,我们感到既熟悉又陌生。它是ASP.NET Web Form的一个增强,一个替代,还是一个替补?我们做Web开发两者都需要了解掌握吗……

相信很多朋友和我一样,在学习ASP.NET MVC的路上会遇上许多疑问,以至于甚至很多人只是大概了解下,感觉和ASP.NET Web Form差不多。

本文,就是总结一些自己学习过程中的随想,希望能给你解一些惑。

0. Web是怎样工作的

有助于理解ASP.NET Web Form和ASP.NET MVC之间区别和更好学习ASP.NET MVC的重点之一就是要理解Web是怎样工作的。

相信很多人有这样的经历:在使用ASP.NET控件轻松创建Web页面入门Web开发之后,却会被ASP.NET复杂的页面生命周期,服务器控件,页面回 调这样一些概念搞得晕头转向。以至于许多像我一样的初级程序员被一个控件和页面生命周期的准确描述和理解被面试长官拒绝无数次,这里当然有个人的技术熟练 度和没有努力等问题,但是不免也会疑问,Web真的有这么复杂么?

我不是计算机专业毕业,没有学过网络技术。但是我相信,像Web的工作原理,HTTP等这样一些概念,即便是学过理论也需要在工作中的不断接触才会有更深 的理解。我对软件开发的学习是从ASP.NET开始的,在此之前我不知道Web是怎样工作的,因此一路走来,就像一个成绩不好的孩子,每一个问题都是要老 师讲了之后才知道怎样做,从来不敢说自己掌握了技术。其实这样也好,学到一点小小的技巧都会感到很高兴。

直到看了《RESTful Web服务》,才开始关注Web的工作原理。这本书讲的是REST,可事实上REST是Web的最佳体验,可以说是你必须理解Web的基本工作原理,才能 理解REST的概念。在看了这本书以及之后看过一些HTTP相关的书籍和文章之后,才恍然大悟,原来Web是简单的。

它简单得就像我们现在的短信通信:你发送一条消息给另一个人,而另一个人给你回复一条信息。

我们应该都了解移动联通等短信服务,我们看一条联通的短信服务(10010):

0.3G专区

1.话费及积分

2.账户查询

3.客户服务

4.业务办理

5.增值业务

6.省份专区

请直接发送相应序号到10010进行业务办理.

这样的短信服务,相信大家并不陌生。10010是一台短信服务器,它有很多信息,如果你想看关于3G的信息,你就发送0到10010;10010根据请求 短信中的序号知道你是要咨询3G业务,于是就把3G相关的一条短信发给你。其中的序号是一个标识,它告诉服务器应该响应哪条信息。

Web其实也是这样的,客户机发送一条消息给服务器,服务器回一条消息给客户机。并且两者之间传输的仍然是像短信一样的文字,只不过其中的标识复杂了,因 为Web的文档远不像短信那么简单,Web服务器有大量的文档,每种文档有复杂的格式,并且这些文档内容可能是动态生成。因此这个请求的标识变得复杂,它 可能包含大量的信息,比如请求的文件类型,请求文档的编号,路径,以及其他大量相信。而服务器能够理解这个“复杂的标识”,能根据这个复杂的标识猜出客户 机想要的具体的文档内容和类型。并且除了文档内容,服务器仍然可能附带复杂的标识信息,比如告诉客户机这是一个Word文档,你还可以用Word相关工具 打开这个文档。

看,Web就是这么简单。它就是关于向服务器发送一个文档以请求另一份文档的事。为了相互之间能给更好的协调,每个信息另外加上一些大家都能懂的标识,这 就是HTTP协议。比如请求部分包含Header,HTTP版本,主机地址路径,请求的具体信息(Body)。

就这么简单的事,可是ASP.NET就要发过来再回调过去,搞得没完没了的,真实晕头转向。

1. ASP.NET,ASP.NET Web Form和ASP.NET MVC

其实很多时候我们把ASP.NET和ASP.NET Web Form当做一回事了,认为.NET的Web开发就是ASP.NET了,这里其实是一个小误区。

ti

根据第一节介绍的Web工作机制,我们来分析这张图,这是我手画的草图,存在不完整和不严密的地方,但大体可以这样理解。

IIS是一个网络组件,属于TCP/IP协议的应用层,你安装,或者不安装,它就在那里!^_^

IIS有2个主要基础功能:1,接收传输层的数据,并把数据传递给上层应用程序如(ASP.NET)。2,接收上层应用程序的数据,并把数据发送给传输层发送到Internet网络。

所以,ASP.NET只是IIS服务器组件的一种接收和处理数据的方式。IIS提供了接收和处理数据的能力。ASP.NET提供一种开发Web应用程序的 基本框架和基础能力。你不用Web Form或者MVC,仍然可以开发ASP.NET应用程序。并且还可以有其他的应用程序框架来和IIS交互。

我们所知道的IHttpHandler,HttpContext等属于ASP.NET基础框架。ASP.NET基础框架提供的能力大体可以这样理解:

1. 接收来自IIS的原始数据,这个数据就是一个Http请求的数据文本,我们来看一个Windows Azure Storage Service API的例子:

PUT http://myaccount.blob.core.windows.net/mycontainer/myblockblob HTTP/1.1
x-ms-version: 2009-09-19
x-ms-date: Sun, 27 Sep 2009 22:33:35 GMT
Content-Type: text/plain; charset=UTF-8
x-ms-blob-type: BlockBlob
x-ms-meta-m1: v1
x-ms-meta-m2: v2
Authorization: SharedKey myaccount:YhuFJjN4fAR8/AmBrqBz7MG2uFinQ4rkh4dscbj598g=
Content-Length: 11

Request Body:
hello world

任何Web请求的数据都是类似这样的,不管是ASP.NET还是PHP还是Ruby On Rails等。

2. 将这个纯文本转化为HttpContext.Request对象,这使得我们可以获取请求中的信息,从而做出相应的事情。比如Url,Headers,Param,Stream等等

3. 提供一种方式让开发者可以编辑响应文本。不管是转发一个静态文件,还是动态构造一个文档,你可以在继承自IHttpHandler的一个类中自由发挥。你 可以设置Header,Body,响应代码等。这些可以设置在HttpContext.Response对象中。

4. 将开发者编辑的对象(HttpContext.Response)转化为响应文本,以下是一个例子:

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-MD5: sQqNsWTgdUEFt6mb5y4/5Q==
Date: Sun, 27 Sep 2009 22:33:35 GMT
ETag: 0x8CB171BA9E94B0B
Last-Modified: Sun, 27 Sep 2009 22:30:15 GMT
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0

5. 把这个文本发送给IIS。

IIS再转发给传输层,传输层将内存中的数据添加到网际层,网际层把这些数据发送到Internet。

但是如果一个站点全是用IHttpHandler来开发,这无疑是很麻烦的,事实上我们可以自己来处理请求和响应文本,ASP.NET这提供了基础的 Web开发能力。为了提高效率我们需要另外的模板化的方式来设置响应文本,这就是Web Form。而IHttpHandler作为了一种高级的开发,也转化为某些在Web Form不能处理的一种替补。

所以,为了提高一种模板化的方式高效的开发ASP.NET 应用程序,微软推出Web Form‘。它提供一种模板的机制编辑Html,并且提出Web服务器控件这样一种概念,使我们既可以对aspx页面直接编辑,也可以与后台交互,比如取值和赋值。

然而Web Form过于热心,本来每一次用户提交,点击一个按钮都是一次不同的交互,都要遵循前面描述的过程。Web Form为了使开发者更方便的获取请求信息(控件的值),从而弄出回调这样的机制,我们开发确实简单了,直接在后台获取某个控件的引用就可以取值。但是我 们看到这确实与Web的简洁简单大大违背的,并且使很多开发人员远离了对Web工作机制的真正理解。

而ASP.NET是另一种模板化的开发Html页面的机制。它更遵循Web的工作方式,我们后面会分析。

所以ASP.NET MVC仍然是基于ASP.NET,这就是许多人纳闷:MVC好像是另一种全新的方式,为什么还跟ASP.NET有关系,莫非这个MVC不纯,不正宗?看了这样的分析,相信你会明白。

而且,你会觉得开发一个自己的ASP.NET XXX都是可能的。O(∩_∩)O哈哈~

2,从可测试性角度理解ASP.NET MVC

对精通ASP.NET Web Form的朋友来说,显然对于ASP.NET MVC感觉有点多余,比较ASP.NET Web Form已经比较强大足以处理所有需求。那如果它仅仅是另一种替代方式,那学习就没有多大意义了。

可是为什么许多人说ASP.NET MVC才是未来呢?

如果你买了一本和绝大多数ASP.NET Web Form的书一样的,教你怎么使用控件或者怎样开发的书,估计你很难弄清这个问题。事实上很多书光明正大的在封面上写着ASP.NET教程,里面却讲着 Web Form,Web服务器控件,这本身是有概念错误的。

我建议的书籍是《ASP.NET MVC实战》(ASP.NET MVC In Action),当然其他书我没有看不好评价(但是不难猜测许多和以前的asp.net教程一样的书)。这本书有两个理由值得推荐:

1. 讲MVC背后的开发思想,而不仅仅是技术

2. 强大可测试性,可测试性是学习ASP.NET MVC的关键

这一节,我们就从可测试性角度来分析。

相信只有比较有经验的开发者才会在ASP.NET Web Form中使用单元测试,一般人不会有这种概念。这不仅是开发者自己的意识和技能问题,ASP.NET Web Form本身是不易于测试的。

在ASP.NET Web Form中,后台代码(.aspx.cs)和页面(.aspx)耦合在一起。有人说这两个文件明明不是分开的么,但是请问这两者之间可以独立存在么?不要 说用多个aspx页面指向一个aspx.cs文件,这样同样不是独立。在.aspx.cs页面中,大量存在着aspx中的控件引用,离开aspx就无法生 存。这就是Web Form为了让开发者最方便的获取请求中的信息(控件的值)所设计的这样一种方式。结果使得我们想分离出一个逻辑功能很困难,因为几乎所有aspx.cs 中的方法都涉及控件的引用(取值和赋值),也许你可以定义一个分离的类中包含某个控件,但是请问怎样构造这个控件来做单元测试,也许你又会说在最下面定义 一些参数,在调用的时候做一次控件值到参数的转换。问题是你会这么做么?

所有的罪魁祸首在于回调,在于Web Form试图让开发者最简单的和页面交互。

而ASP.NET MVC抛弃了这种思想,把两者之间完全隔离开来,这不仅分离了职责,并且没有了控件引用实行了可测试性。当然这只是实现可测试性的其中一个方面。

3. 重大区别之一—更符合Web工作机制,去掉Page复杂的生命周期

在ASP.NET MVC中没有了回调机制。

ASP.NET的工作流程如下:

1. ASP.NET MVC从ASP.NET基础框架获取请求数据(这和Web Form一样)

2. 路由到正确的Controller中的Action

3. Action准备要显示的数据ViewData,并将ViewData传递给View

4. View按模板显示ViewData中的数据,ASP.NET MVC后面会按模板定义转化为Html文本

5.用ASP.NET基础功能将Html页面发送出去

之后,发送到客户机的也没将不会和Action有任何关系,不需要回调回去取值,这就看起来更像Web的工作机制。

4. 重大区别之二—Controller传递对象而不是直接给View中的控件赋值

那ASP.NET MVC是怎样实现这种分离的。秘密在于传递对象而不是直接赋值。

在ASP.NET Web Form中,后台程序需要获取页面中控件的值,因此需要把整个页面回调会服务端。但是ASP.NET MVC取消了这个机制,因此我们只能按传统的表单的方式取值了。而Action对于View中控件的赋值,却转化为传递一个 Dictionary<string,object>对象,这样Controller和View之间唯一的耦合只是View的名称。而视图的 唯一任务是将对象转化为HTML。因此在ASP.NET MVC中几乎没有了控件的概念,因为View中的控件不需要被引用,它们仅仅是一个现实HTML的面板而已。

由此可见在ASP.NET Web Form中从aspx页面控件取值和赋值的可能性被去掉了,这使得Action中不再具有无法构造的控件引用,而只是普通的参数,因此使得测试成为可能。

5. 可测试性的深入讨论

学习ASP.NET MVC,我们知道,用户提交的表单数据,或者Url中的参数被自动提取为Action的参数,这使得Action中的参数总是可构造的。然而完整的可测试性还应该考虑以下问题:

ASP.NET MVC只能从请求信息中提取Url参数和表单数据,如果需要获取Header,Stream,仍然需要与ASP.NET运行时关联,及 HttpContext,这个对象在Web Form时代是不可构造的,因此也是不可测试的。当然据说ASP.NET MVC提供了可以构造的HttpContextBase等可构造的对象,因此使得这样的需求可以实现单元测试。这是一大好消息。只要在ASP.NET层面 提供了运行时对象的可构造,这样所有ASP.NET XXX都是易于测试的了,当然在ASP.NET Web Form中控件还是不可构造的,因此只能说,目前ASP.NET MVC是完全可测试的。

同时,弱耦合式MVC模式的重要思想。这不仅是软件设计原则,使得软件更具有可维护性,同时他也是可测试的重要因素之一,在高级ASP.NET MVC开发者我们还会学习Ioc这样的思想。它都是使软件可测试和可维护的重要体验。

由此,我们也可以看出,在学习ASP.NET过程中,可测试性观念的重要性。往往因为一般ASP.NET开发者没有这样的观念因此会简单的理解ASP.NET MVC的地位。

6. ASP.NET MVC与ASP.NET Web Form并存,互补

当然ASP.NET MVC与ASP.NET Web Form之间不是非此即彼的关系,它们可以并存于同一个应用程序中。我们可以从他们之间的关系去理解这一点,它们都是基于ASP.NET的一个模板化开发方法。

ASP.NET Web Form提供比ASP.NET MVC要强大很多的方法,并且我们大多数多Web Form的机制非常熟练了。但是随着Ajax的广泛应用,ASP.NET MVC简洁的模式会更受欢迎,并且它符合Web的理念,更重要的,它更易于测试,从而保证项目的质量。从某种程度上说,从ASP.NET MVC中的可测试性或者的软件质量保障的好处,也许会高于从表单获取数据没有Web Form高效的地方。当然,我对ASP.NET MVC也只是在学习的路上,也许ASP.NET MVC和Web Form一样强大。

7. 高级ASP.NET开发

不管是ASP.NET Web Form还是ASP.NET MVC,或者你自己实现的ASP.NET XXX,这些都不是实现完整的Web开发。

模板化的开发方式只是面向浏览器的,它构造的是HTML页面。如果你实现的服务不是面向浏览器,而是面向应用程序,这样的框架就不行了,所以我们构建 WCF不能使用ASP.NET Web Form或者ASP.NET MVC,它实际上又是基于ASP.NET的另一个框架。

并且,很多时候我们发现Web Form无法做到的事情,只能用IHttpHandler来实现,记住ASP.NET Web Form和ASP.NET MVC都是原来实现面向浏览器的高效开发的。

反过来,理解了ASP.NET运行时机制,可以很好的学习任何ASP.NET XXX框架。在这之上,你开发一个自己的Web框架都是可能的。事实上笔者正在构造在ASP.NET上开发REST API的框架,它类似于WCF,但是REST风格的,当然也不同于WCF Data Service。

我们看到不论是我的REST框架,还是WCF,还是ASP.NET Web Form,还是ASP.NET MVC;这些都是基于ASP.NET基础框架。ASP.NET是一个强大的Web框架,不要拿Web From所能做的事情当做是ASP.NET所能做的事情。

8. 总结

胡言乱语,没有逻辑,随想随写,切莫道听途说,如有误导,深表歉意!

[转载]构建高性能ASP.NET站点 第五章—性能调优综述(前篇) - ASP.NET 架构 - 博客园

mikel阅读(952)

[转载]【原创】构建高性能ASP.NET站点 第五章—性能调优综述(前篇) – ASP.NET 架构 – 博客园.

前言:这段时间,把系列文章又重新整理了一下,之前关于性能优化的介绍一些不是很清晰。可以说从本篇开始,才算是一个完整的系列的开始。

本章的议题如下:

性能调优的一般过程

利用分析工具分析页面加载信息

利用分析工具分析性能瓶颈

性能调优的一般过程

在解决性能问题之前首先要确认问题的所在,首先就来看看确保高性能的一般过程:

1. 持续监控

2. 设定性能目标

3. 持续改进

1. 持续监控

网站的性能总体来说受两个方面的影响:

一,我们可以控制的,例如代码;

二,我们不能控制的,例如访问用户的数量,或者服务器本身

特别是随着站点的访问量增大的时候,原来没有出现的问题,现在可能出来了,不同的阶段要解决的问题也是不一样的。所以很有必要对网站进行持续的监控, 趁早发现网站变慢的原因。本篇的后面部门会介绍一些我们可以使用的监控服务,来帮助我们做这些事情。

2. 设定性能目标

网站的性能如何,一个最直观的感受就是:打开这个站点之后,页面加载的时间,这也是说是访问者最直接的体验。很多的优化工作(不管是前台的优化还是后台的优化)都是为了让用户更快的看到所想看的页面和信息。我们后面的讨论很多时候都是以这个为目标的。

首先必须要明白“快”的含义:一个网站的响应速度多快才算是“快”?因为优化网站需要花费很大的时间和精力,如果网站本身已经很快了,例如网页呈现到用户眼前的时间是毫秒级别的,我们确实可以再花时间让它更快,但是这样做起来成本会更高!

3.持续改进

在进行性能优化的时候,要涉及到很多的东西,所以在进行优化的时候必须确认:进行的优化措施确实的提高了站点的性能。为了达到这个目的,有几个规则可以遵循:

1. 每次优化只改动一处。如果改动了很多处,那么这些改动之间可能相互的影响,最后产生一些奇奇怪怪的现象,有时候这些优化措施反而使得网站性能降低。而且如果一次改动多次,也不利于衡量那些优化措施真真正正提升了网站的性能。

2. 不断的测试。每次进行了所谓的优化之后,一定要测试一下,这个优化是否真的提升了性能,如果没有提升,那么就回滚这个操作。

一般进行优化的步骤如下:

1. 记录现在网站的性能指数和一些相关的数据(后面会告诉大家如何获取这些性能指数数据)

2. 诊断站点的性能故障点.可能有几个地方都影响了站点的性能,但是,此时我们只是选择影响最大的那个因数进行优化。

3. 解决找出的性能故障点。

4. 测试。收集数据,和优化前进行比较,看看是否提升了性能。

5. 重复14步骤。

上面虽然提出了一些规则,但是我们可以灵活处理某些情况:在我们查找影响性能的问题的时候,我们发现多个问题,而且这些问题根据我们的经验判断会影响性能,那么我们可以同时修改此处。

我们用一个流程图来总结上面的优化步骤。如下:

OK,今天就暂时发布这些,下一篇发布:利用分析工具分析性能瓶颈。

很有段时间没有更新博客了,多谢大家一致以来的关注和支持,在新的一年里,努力为大家提供更多的博文,算是对朋友们的回馈,小洋再次感谢大家! :)

[转载]关于ASP.NET预编译

mikel阅读(1241)

[转载]关于ASP.NET预编译 – dudu – 博客园.

为什么要用预编译?

博客园博客程序中.aspx和.ascx文件总共加起来有3000多个(博客模板中有大量的.ascx文件)。如果使用动态编译,每次只要更新 bin文件夹中的任何一个dll文件,动态编译至少需要5分钟(访问量越高,所需的编译时间越长),而在动态编译期间网站访问速度极慢,几乎就是无法正常 访问。这样,每次更新程序成为了一种痛苦,只能安排在深夜或一大早。

面对这样的情况,只能选择预编译。

预编译的原理是什么?

请阅读Artech写的深入剖析ASP.NET的编译原理之二:预编译(Precompilation)

如何进行预编译?

用aspnet_compiler命令,命令示例:

aspnet_compiler -v \ -p G:\SourceWebSite G:\TargetWebsite -fixednames

参数说明:

-v \  要编译的虚拟路径,这里表示根路径。

-p G:\SourceWebSite 要编译的源Web项目所在文件夹。

G:\TargetWebsite 编译目标文件夹。

-fixednames 每个.aspx与.ascx文件都编译生成单独的dll文件,并使用固定文件名。

编译情况分析

1. 源文件夹中的所有.aspx, .ascx及App_Code中的.cs文件都会被编译。

2. 编译中遇到任何一个错误,会立即停止编译,并清空目标文件夹中已生成的文件;解决了引起编译错误的问题后,只能从头重新进行编译。出现编译警告,只提示,不影响正常编译。

3. 编译完成后,aspnet_compiler会将.aspx, .ascx, .cs之外的所有文件原封不动地复制至目标文件。(如果编译只是为了更新网站程序,这个操作显得多余。aspnet_compiler没有提供取消这个操作的参数)

4. 3000多个.aspx,.ascx文件,使用-fixednames编译,耗时30分钟左右;不使用-fixednames编译,只要6分钟。 -fixednames编译本来是为了更新方便(每次编译生成的文件名相同,更新生产环境中的dll时直接覆盖就行),没想到这么慢。不用 -fixednames编译,每次更新时,要先删除原来的文件,再复制。在生产环境中,这个操作会短暂影响网站的正常访问。

为什么不用“可更新的预编译(Updatable Pre-compilation)”

Updatable Pre-compilation只编译App_Code中的文件以及.aspx,.ascx的code behind文件,我们的Web项目类型是Web Application,code behind已经编译了,App_Code中也没有代码,相当于已经处于这种编译状态,但还是需要至少5分钟的动态编译时间。

这种编译方式只是减少了编译.cs文件的工作量,但每个.aspx,.ascx文件还是要动态编译,不能避免动态编译的性能问题。

Updatable Pre-compilation适用于App_Code中有大量代码(更新其中的文件会引起该文件夹中的所有文件重新编译),又不想用Non-updatable Pre-compilation的情况。

结论

面对这么多的.aspx,.ascx文件,只能选择预编译。-fixednames编译实在太慢,只能放弃。更新时只能先删除,再更新。虽然有些不足,但总比动态编译好。

当然,真正的解决之道是干掉模板中的那些.ascx文件。ASP.NET MVC会是救星吗?