2015年6月15日星期一

七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC - 葡萄城控件技术团队

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
七天学会ASP.NET MVC (一)――深入理解ASP.NET MVC - 葡萄城控件技术团队  阅读原文»

Day1

ASP.NET vs MVC vs WebForms

许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上ASP.NET是创建WEB应用的框架而MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系,所以可以称之为ASP.NET MVC。

我们可将原来的ASP.NET称为 ASP.NET Webforms,新的MVC 称为ASP.NET MVC.

ASP.NET Web Form

ASP.NET 在过去的十二年里,已经服务并成功实现Web 应用的开发。我们首先了解一下为什么ASP.NET能够如此流行,并成功应用。

微软编程语言从VB开始就能够成为流行并广泛应用,都源于其提供的强大的Visual studio能够进行可视化的编程,实现快速开发。

使用VS时,开发人员能够通过拖拽UI元素,并在后台自动生成这些界面的代码。称为后台代码。在后台代码中开发人员可以添加操作这些UI元素的逻辑代码。

clip_image002

因此微软的可视化RAD架构体系有两方面组成,一方面是UI,一方面是后台代码。因此ASP.NET Web 窗体,包含ASPX和ASPX.CS,WPF包含XAML/XAML.CS等。

ASP.NET Web Form存在的问题

我们不得不考虑的问题是,既然ASP.NET Web Form 如此成功且具有优势,为什么微软还要推出ASP.NET MVC?主要是因为ASP.NET Webform的性能问题。在Web应用程序中从两方面来定义性能:

1. 响应时间: 服务器响应请求的耗时

2. 带宽消耗: 同时可传输多少数据。

响应时间

我们可以理解为什么ASP.NET Webform比较慢,如图我们做了一些小的加载测试。分别使用ASP.Net MVC和ASP.Net Webform,发现ASP.Net MVC的响应时间比Webform快了两倍。

clip_image003

接下来我们在思考一个问题为什么ASP.NET MVC的性能更好?看看下面这个示例,简单的UI代码和UI的后台代码。

假如一个textbox的ASPX页面:

<asp:TextBox ID="TextBox1" runat="server">

对应的UI后台代码:

1: protected void Page_Load(object sender, EventArgs e) 2: { 3: TextBox1.Text = "Make it simple"; 4: TextBox1.BackColor = Color.Aqua; 5: }

运行结果:

clip_image004

如果查看HTML输出,则会显示如下代码:

<input name="TextBox1" type="text" value="Make it simple" id="TextBox1" style="background-color:Aqua;" />

我们再来思考上面提到的问题

1. 这种HTML生成方式是否很有效?我们是否为了获取如此简单的HTML而长时间的消耗服务器

2. 开发人员是否可以直接编写HTML?很难实现吗?

clip_image005

通过分析我们可以得知,每一次请求都有转换逻辑,运行并转换服务器控件为HTML输出。如果我们的页面使用表格,树形控件等复杂控件,转换就会变得很糟糕且非常复杂。HTML输出也是非常复杂的。由于这些不必要的转换从而增加了响应时间。该问题的解决方案就是摆脱后台代码,写成纯HTML代码。

带宽消耗

ASP.NET开发人员都非常熟悉Viewstates,因为它能够自动保存post返回的状态,减少开发时间。但是这种开发时间的减少会带来巨大的消耗,Viewstate增加了页面的大小。在做的加载测试中,与MVC 对比,我们发现Viewstate增加了两倍的页面存储。以下是测试结果:

clip_image006

页面尺寸的增加是因为viewstate产生了额外的字节。下图就是Viewstate的截图。许多人可能会不同意此观点,但是众所周知,开发人员是如何工作的,如果有选择,他们肯定会采取别的选择。

clip_image008

  1. HTML 消耗

现在因为我们都是后台代码和ASP.NET web server控件的努力,我们对于怎样得到HTML以及如何使他们更有效没有更好的办法。如下面展示的ASPX 代码,你能确定会生成什么样的HTML代码吗?


  • <asp:Label ID="Label1" runat="server" Text="I am label">


  • <asp:Literal ID="Literal1" runat="server" Text="I am a literal">
  • Nim教程【十】 - liulun  阅读原文»

    openarray类型

    注意:openarray类型只能用于参数

    固定大小的数组虽然性能不错,但过于呆板,使用取来不是很方便

    对于一个方法来说,传入参数如果是一个数组,最好是不要限制数组的长度

    也就是说,方法应该能够处理不同大小的数组

    openarray类型就是为了满足这样的要求而设计的

    openarray类型的变量索引总是从0开始

    len、low、high等操作同样试用于openarray类型

    原则上,任何一个数组都可以被传递到一个openarray参数中,索引的类型并不重要

    但是一定要注意:不能给openarray类型的参数传递多维数组

    可变数量的参数

    一个可变数量的参数就是一个openarray参数

    他可以让开发者传递多个同一类型的参数给一个方法

    编译器自动将这些参数转换为一个openarray数组

    proc myWriteln(f: File, a: varargs[string]) =
    for s in items(a):
    write(f, s)
    write(f, "\n")

    myWriteln(stdout, "abc", "def", "xyz")
    # is transformed by the compiler to:
    myWriteln(stdout, ["abc", "def", "xyz"])

    需要注意的是:这种类型的参数必须是方法签名的最后一个参数

    另外,你可以通过下面这种方式来动态转换传入的参数的类型

    proc myWriteln(f: File, a: varargs[string, `$`]) =
    for s in items(a):
    write(f, s)
    write(f, "\n")

    myWriteln(stdout, 123, "abc", 4.0)
    # is transformed by the compiler to:
    myWriteln(stdout, [$123, $"def", $4.0])

    在这个例子中,$应用于任何参数,

    (注意:$应用于字符串时,是一个nop操作)

    (译者注:这个语言特性非常像C#里的param关键字)

    slice类型

    slice类型和subranges类型很相似

    但这两个类型的使用场景不尽相同

    在实际的业务控制代码中slice类型并不是很常用

    但在很多集合类型的操作中,slice起到定义操作数的作用

    请看下面的代码:

    var
    a = "Nim is a progamming language"
    b = "Slices are useless."

    echo a[7..12] # --> 'a prog'
    b[11.. -2] = "useful"
    echo b # --> 'Slices are useful.'

    在上面的例子中,slice类型被用于修改一个字符串的一部分

    在上面的例子中,-2是一个负数索引(倒数第二个字符)

    理论上slice可以容纳任何类型的数据

    但是如果slice用于方法的签名中,则必须明确slice容纳的数据类型

    Tuple元组类型

    Tuple元组类型定义了一系列的有序的属性

    可以使用方括号来定义元组,

    使用小括号来构造元组,

    构造器中属性的顺序必须和元组定义的属性的顺序一致

    如果两个元组在定义的时候,使用了相同的属性而且属性的顺序也是一致的

    那么这两个元组就是相同的

    可以使用t.field来访问一个元组的某个属性

    也可以使用t来访问一个元组的第几个属性

    来看下面的代码:

    type
    Person = tuple[name: string, age: int] # type representing a person:
    # a person consists of a name
    # and an age
    var
    person: Person
    person = (name: "Peter", age: 30)
    # the same, but less readable:
    person = ("Peter", 30)

    echo(person.name) # "Peter"
    echo(person.age) # 30

    echo(person[0]) # "Peter"
    echo(person[1]) # 30

    # You don't need to declare tuples in a separate type section.
    var building: tuple[street: string, number: int]
    building = ("Rue del Percebe", 13)
    echo(building.street)

    # The following line does not compile, they are different tuples!
    #person = building
    # --> Error: type mismatch: got (tuple[street: string, number: int])
    # but expected 'Person'

    # The following works because the field names and types are the same.
    var teacher: tuple[name: string, age: int] = ("Mark", 42)
    person = teacher

    从上面的代码中,大家可以看出

    在使用tuple类型的时候,不一定要新创建一个类型出来

    上面的代码中的building变量就直接使用了tuple类型,而不像person一样先创建了一个Person类型

    只有在元组属性赋值期间元组才可以被拆箱(这里不知道翻译的对不对,原文:Tuples can be unpacked during variable assignment (and only then!).)

    os模块的内置splitFile方法,可以返回三个值,一个是路径,一个是文件名,一个是文件扩展名

    这个时候就可以应用这个特性

    import os

    let
    path = "usr/local/nimc.html"
    (dir, name, ext) = splitFile(path)
    baddir, badname, badext = splitFile(path)
    echo dir # outputs `usr/local`
    echo name # outputs `nimc`
    echo ext # outputs `.html`
    # All the following output the same line:
    # `(dir: usr/local, name: nimc, ext: .html)`
    echo baddir
    echo badname
    echo badext

    上面的代码第一次输出和第二次输出是一样的

    只有使用var或者let操作符时,才可以应用元组解包的特性

    下面的代码编译不会通过的

    import os

    var
    path = "usr/local/nimc.html"
    dir, name, ext = ""

    (dir, name, ext) = splitFile(path)
    # --> Error: '(dir, name, ext)' cannot be assigned to

    今天就写到这里吧,喜欢的请帮忙点个推荐

    谢谢大家


    本文链接:Nim教程【十】,转载请注明。

阅读更多内容

没有评论:

发表评论