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

mikel阅读(964)

[转载]教你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阅读(1056)

[转载]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阅读(857)

[转载]构建高性能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阅读(1180)

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

内容采集系统,对于以内容为主的网站来说是非常好的助手,除了原创内容外,其它内容需要 编辑人员或者采集系统来收集整理,然后添加到自己的网站里。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阅读(1051)

[转载]如何将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阅读(879)

[转载]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阅读(951)

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

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

本章的议题如下:

性能调优的一般过程

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

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

性能调优的一般过程

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

1. 持续监控

2. 设定性能目标

3. 持续改进

1. 持续监控

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

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

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

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

2. 设定性能目标

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

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

3.持续改进

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

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

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

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

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

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

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

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

5. 重复14步骤。

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

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

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

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

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

mikel阅读(1237)

[转载]关于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会是救星吗?

[转载]使用python对txt格式的小说进行处理

mikel阅读(1120)

[转载]使用python对txt格式的小说进行处理 – lifehacker – 博客园.

vim的确是神器,可惜sed与vim不完全通用。这篇文章受《 用vim对txt格式的小说重新排版》的启发,在此致谢!

经常下载txt的电子书,格式却不合心意,只好自己再处理。首要的就是处理段内换行。

原来的打算是定制一个vim模式,到时候处理小说时进入该模式,再使用各种快捷键。以此避免txt快捷键对日常编程的干扰。后来发现,vim不像emacs,可以定制自己的模式。(可能可以定制专用的vimrc解决,未经尝试)

于是转向脚本寻求解决办法。sed与awk是此中翘楚,首先试试。可惜早些日子学的sed已经忘的差不多了,找不到比较简洁清晰的解决办法。sed 与grep类似,先读入一行,删除\n,进行各种处理,最后写入文件,再添上\n。 N可以读入下一行到当前模式匹配空间再行处理。但是我需要对整个文件进行匹配,暂时未找到解决办法。

只好再次转投python。Python有自己的re模块,应该没问题。re.sub可以进行替换。费了些时间的,是对中文的匹配。在vim中,可 以用[^\x00-\xff]匹配双字节字符,然而python中却行不通。经过一番google,发现可以用[\x80-\xff]匹配汉字(perl 同此,似乎两者对中文的正则支持还是有待改进)。

至此,问题初步解决:

01 #!/usr/bin/env python
02 #encoding=utf-8
03 import re
04 from sys import argv
05
06
07 if __name__ == '__main__':
08 if len(argv) != 2:
09 print 'usage: filename'
10 else:
11 fh = open(argv[1], 'r')
12 content = fh.read()
13 out = re.sub('\n([\x80-\xff])', r'\1', content)
14 print out

规范行首:

01 #!/usr/bin/env python
02 #encoding=utf-8
03 import re
04 from sys import argv
05
06
07 if __name__ == '__main__':
08 if len(argv) != 2:
09 print 'usage: filename'
10 else:
11 fh = open(argv[1], 'r')
12 content = fh.read()
13 out = re.sub(' +([\x80-\xff])', r'     \1', content)
14 print out

当然,下载来的文档通常是GB2312,需要自己转换为utf8再行处理,可以参考我的《python 中文编码笔记》

在win下,有个优秀的文本处理工具可以利用,叫cnbook。在百度的fmddlmyy贴吧可以下载到最新版本。

[转载]不用到处找资料,2天掌握Asp.net Mvc 3

mikel阅读(1429)

[转载]不用到处找资料,2天掌握Asp.net Mvc 3 – 玄歌 – 博客园.

最快的学习方法:找到官方的教程,最好是类似Msdn演练或者冠以Step By Step的,跟着做一遍,做的过程中可以拷贝少量教程中的代码,确保每个步骤、每行代码含义都能够明白,中途随手记录一下,每个步骤完成后停下来在脑子里 回顾一下。教程做完,基本上该掌握的也就掌握了,当然,也有人简单的了解一些后就希望在小型的项目中开始使用,忽略了学习过程,这实际上更为浪费时间。先 系统的学习一下,将会大幅减少开发过程中碰到问题解决问题所需要的时间。

ASP.NET Mvc 3当然也不会例外,官网上两篇教程,看看ASP.NET MVC Music Store就行。已经有人翻译为中文版,不过建议还是看原文,翻译质量不高,原文每篇课程下都有讨论。先简单浏览一下,大体上覆盖范围比较合适,16个小时以内应能够做完。以下是我本人实作过程中的零星笔记。

第一课 创建项目 开始时间2月4日14:00 预期30分钟  14:23结束。

这一课主要讲两个问题,项目要做什么:一个音乐商店,换句话说是卖唱片之类的网上商店。功能方面,网民可以按类别或按照演员是谁来查看唱片,加入购物车, 并实现模拟的支付。管理员能够添加新的唱片。That’s all,这基本上是做典型的小型网上商店的主要需求。

创建项目的过程很简单,注意这里创建的是一个“空的”ASP.NET Mvc3的项目,创建完之后可以看看,除了Content目录下有网站的一些默认的样式和图片之外,神马都没有。之所以创建这样空的项目而不是使用项目模 版,让VS帮助我们实现基本的首页、登录、注册、注销之类的功能,大约是为了让我们从最底层了解代码和编程方式。

这里要注意的要点只有一个:ASP.NET Mvc的默认目录,这些目录下即使没有任何东西,也需要创建,一个Mvc应用会在Controller目录下寻找控制器、会在Views目录下寻找 View,不需要在编程的时候写完整的路径。所以这是ASP.NET MVC开发Web应用的约定。简单的说,这些目录非有不可。

第二课 控制器 开始时间14:23 预期60分钟 15:06分结束 中断4分钟

这一课主要讲怎样为应用添加控制器、在浏览器中如何访问相应的控制器里的相关方法。

1、控制器是什么?实际上是Url,举例来说,http://localhost:1826/Home/Index,对应HomeController的Index方法,我们在浏览器中输入这个地址,则该方法会执行。看看自动生成的代码,这里一般是返回一个视图,本课则用一个返回字符串的方法取代,这样执行的时候,网页上就会显示这个字符串。当然,如果只输入http://localhost:1826/Home/,则默认的使用Index方法,如果连Home也省略掉输入http://localhost:1826,则默认的使用Home控制器。这些同样是约定,没什么道理可说,只是为了方便。

2、控制器的方法名称约定:只问方法名称,不问方法的参数和返回值。上面可以看到,系统生成的index是返回一个View,改成返回字符串的Index,运行时照样能够找到这个方法。

3、方法的参数:另外一个控制器StoreController包括三个方法,分别是Index、Browse和Detail,在浏览器中输入http://localhost:1826/Store/Browse?Genre=Disco,为StoreController的Browse方法提供了一个参数:Disco。在浏览器中输入http://localhost:1826/Store/Details/5,则为Details方法的Id提供了一个参数5.不过,你若是http://localhost:1826/Store/Browse/Disco,这样参数是不能传到的,原因见4.

4、返回字符串的时候,Browse方法使用了HttpUtility.HtmlEncode,防止js注入攻击。http://localhost:1826/Store/Browse/Disco这种情况下将不能获得参数。

string message = HttpUtility.HtmlEncode(“Store.Browse, Genre = ” + genre);

所以总结一下:控制器和Action、参数三者,是构成网站Url的三个部分,其中若不提供控制器名称,则默认的使用HomeController,不提 供方法名称则默认的使用Index方法。参数有两种形式,当接受的参数为字符串的时候,要使用HttpUtility.HtmlEncode防范Js注入 攻击。

这里,可以看看本课最后的总结。

第三课 View和ViewModels 15:15分开始 预期100分钟 16.40结束

本课讲解如何添加视图和ViewModels

1、 视图和控制器的关系:控制器一般推送一个视图给浏览器。前面的Controller中,我们每个Action返回一个字符串,浏览器显示该字符串。但我们 最终仍然还是要自行的生成Html,这就是View的任务。我们并非是在手写htm,而是夹杂着Razor脚本,用来访问服务器资源。从这个角度来说,博 客园的DUDU版主提及的没有必要使用Mvc,其理由是站不住脚的。

2、如何添加控制器:在Controller目录,右键,添加控制器即可。

3、如何添加View:我们先将Home的Index方法恢复原状,即返回ActionResult,同时Return View(),然后在这个方法的代码上,右键,添加视图。一个名为Index.cshtml的视图就会创建。

请注意,这里Return View()的View构造方法有多个重载,使用默认的构造方法,将导致该控制器在Views\Home\下面寻找与Action也就是这个方法同名的视 图,也就是我们刚刚生成的Index.cshtml。这就是前面提到的目录路径和文件名的约定,只是约定而已,目的是让我们的编程更简单些。

index.cshtml这样的文件和以前的Aspx没什么不同,是夹杂脚本的文件,服务器未来将依据其得到htm、css和js,浏览器呈现。

生成的视图代码很简单,前面的三行是Razor语法的说明,用来指定该视图在浏览器里显示时的标题。后面一行则简单的htm语法,显示一行文本。

4、 修改_Layout.cshtml ,这个是站点公用的模版。在Views\Shared目录下面。实际上要关注的是,使用@RenderBody(),来呈现各个视图。我们需要在网站的顶 部显示两个链接,一个到首页一个到Store,那么,先直接在Body这里Render之前加入

5、调整样式:直接从http://mvcmusicstore.codeplex.com下载MvcMusicStore-Assets.zip,打开压缩包,将包里的Content目录拖放到解决方案中。这里只是覆盖了site.css并加入了几个图标,样式已经由这个项目组先制作好了。现在的站点看起来像模像样的了。

6、使用Model传送信息给View:先在Model里增加两个类,Genre用来表达商品的类型,现在我们只需要一个Name属性。Album类,包括包括一个标题和它属于那个类型,两个属性。

然后,编译这个项目,让开发环境知道增加了这两个类,我们再为StoreController的三个方法增加视图。

7、最后,Store的index视图必须能够转到Browse视图,这个通过修改index的Views很容易做到。

到目前为止,我们在顶部有两个链接,其中Store的index方法包含一个类型列表,点击这个列表中的每个成员,都进入相应的Browse页面。

总结一下:如何为控制器的某个Action创建视图?如何为视图指定Models?如何在视图中呈现某个对象或某个集合?

第四课 Models和数据访问 22:08分开始 预期30分钟  23:35分结束,中断16+6+3分钟。其中数据库问题浪费了一点时间。

这一课的主题很简单,如何访问数据库。

准备工作:

1、创建数据库:当然,数据库包括示例数据,已经准备好,在我们上一课中下载的MvcMusicStore-Assets.zip文件里。我们找到Data目录下的MvcMusicStore-Create.SQL,使用它创建数据库。

2、 安装EFCodeFirst包:安装Asp.net mvc3同时也安装了Nuget,可以使用Nuget找到EFCodeFirst包,并安装。通过这个包,我们可以先写代码然后再生成数据库,当然,现在 我们使用的是已存在的数据库。另外一篇向导讲解了如何先写实体类再生成数据库。

接下来:

1、在Web.Config里添加连接字符串:这个是常规工作,和教程里不同,是用SQL server,所以连接字符串为

<configuration>
<connectionStrings>
<add name=”MusicStoreEntities”
connectionString=”Data Source=.;Initial Catalog=MvcMusicStore;Integrated Security=True”
providerName=”System.Data.SQLServer” />
</connectionStrings>

2、在Models中添加一个Context类MusicStoreEntities.cs,这个类继承于DbContext,包含两个DbSet属性分别处理前面的Albums和Genres表格。

只需要这个类无需其他配置,则我们能够正常的处理数据访问操作了。

3、修改前面的Album和Genre类,前面只是简单的描述,现在这两个类的属性要和表格对应起来。

4、然后在StoreController中增加一个成员MusicStoreEntities storeDB = new MusicStoreEntities(); 用来访问数据库

5、现在试试,修改Store的index方法,返回数据库中的Genres表格的内容:

var genres = storeDB.Genres.ToList();
return View(genres);

遇到问题:数据库访问异常。找到原因MvcMusicStore-Assets.zip中的脚本文件不对,直接附加里面的b数据库即可。

6、其它的也就简单了,修改Store的Browse、Details改从数据库获取数据,当然,也要修改Browse的视图

这样,我们现在在首页点击Store,能看到类别列表(Index)。点击任一类别,能看到该类别的所有商品了(Browse)。

总结:这一节讲解我们的Controller如何透过Modes从数据库中获取主从数据,当然,用Ado.net等方式也是相同的,和上一课没什么不同,区别是数据来源不一而已。

第五课 CRUD操作 11:08分开始 预期60分钟  13:19分结束 中断12+9分钟

本课讲解:如何增加新的记录、修改记录和删除记录

1、首先要创建一个StoreManagerController,当然,此时要勾上“为创建、更新、删除和详细信息添加操作方法”。由于详细信息这个对我们没用,可删除该方法。

2、 此时要加入唱片的“演员”信息,这包括创建一个演员类Artist,为每张唱片增加Artist属性,同时在前面的Context中增加一个Artist 的DbSet,当然我们也要为StoreController增加一个MusicStoreEntities对象用于访问数据。

数据库已经建好,所以只要Context中的DbSet名称与表格名相同、属性名称与字段名相同,我们不需要做其他的事情,根据命名约定EF会自动处理这 些。我们现在为唱片类增加了一个Genre对象、一个Artist对象,表示该唱片属于哪个类别和演员是谁,注意这两个使用Vitual修饰的属性,它不 是对应表格中实际的字段。我们也为该类增加了一个链接字段,用于存放唱片的图片的链接。

3、实现Index方法,并创建视图,这个要显示 各个唱片,所以Model选择Album类,视图要选择List,VS将帮我们生成列表的代码,注意自动的将Model设为 IEnumerable<MvcMusicStore.Models.Album>。我们修改一下,只显示唱片的标题、类别和演员,并去掉 Detail按钮。

运行一下,在浏览器地址栏输入http://localhost:1826/StoreManager,可以看到列表。

4、自己创建HtmlHelper方法,防止字段过长影响Table的布局:我们可以创建一个新目录Helper,创建一个静态类,在其中为HtmlHelpers类增加一个扩展方法。

5、如何使用扩展方法:在视图中引用命名空间即可

6、实现Edit:应该看到Controller中生成了两个Edit方法,前者是用来显示该对象的,后者是用来提交编辑结果的。我们实现了Edit的Get方法后,为其创建Edit视图。

两种方法:一种是使用添加视图由Vs自动创建,一种是使用Heml.EditorFor,我们创建好视图之后修改一下,使用后面一种方法。这样是为了这个视图可以重用于Create。

7、模版的命名约定:我们使用HtmlEditFor来编辑某个Model的时候,系统会首先在Views下面寻找EditorTemplates目录,看下面是否有与Model同名的模版,如果有则使用这个模版,否则创建默认的视图。

所以文件夹的名称和文件的名称都是有强制性的约定的。这当然是ASP.NET MVC强调约定大于配置的理念。

8、创建共享的模版:我们在Views的Shared目录下创建文件夹EditorTemplates,然后在这个文件夹添加一个名为AlBum的视图,并勾上“创建局部视图”。

将模版中的Form相关的信息删除掉,包括提交按钮等,窗体和提交由使用该模版的视图处理,这里的编辑视图仅仅处理对每个字段的编辑。

9、现在我们要修改模版,比如类别和演员,这个通过选择而非输入来处理。这就意味着我们必须使用ViewBag将所有演员的列表和所有类别的列表传入。

10、然后实现HttpPost方法,这里要注意的,是如果提交不成功,两个下拉框用的列表应重新载入。当然,实际项目开发过程中,至少应在服务端缓存这两个列表。

现在就已经能够编辑并保存数据了。

接下来:实现Create方法,这里要重用刚刚创建的编辑模版。实现Create的Get方法,添加视图、改用重用的Edit模版、实现Post方法,这些都照本宣科的做就行了。

12、处理删除:

这个过程包括Get方法,这实际上是一个确认过程。包括Post方法,这里需要一个非强类型的视图告知已经被删除。

总结一下,这一课重点是以下内容:

1、增删改的Get、Post方法和相应的视图。

2、如何创建自定义的HtmlHelpers方法,如何使用?

3、如何重用视图

4、如何处理下拉框,如何使用ViewBag传送数据?

这一课真的头昏脑胀,时间太长,签入代码的时候竟然有舒了一口气的感觉,教程内容安排太不均衡。

完成第五课

第六课 验证  13:35分开始 预期15分钟 13:43分结束

对用户的输入进行验证,包括客户端和服务端两种情形。本课内容很简单,直接在Model里定义验证规则,不用做任何其他的事情,就能解决基本验证问题。