zoukankan      html  css  js  c++  java
  • ASP.NET MVC4 Web 编程第六章

    部分渲染

    向服务器发送http请求,并从服务器接收Http标签是万维网的基础,因此,向服务器再次请求html标签来更新网页的内容也合乎情理,这种犯法就叫做“部分渲染,属于ajax的基本过程”

    部分渲染技术包括发送异步请求给服务器,服务器返回包含html代码的数据插入到对应的页面区域。

     这个例子使用了元素来标记要插入的元素,也可以使用jquery.load()请求服务端内容来更新这个元素:

     .load()方法向服务器发送异步请求,然后把内容插入#container元素,调用返回之后dom将会动态更新元素的内容:

    正如例子所示,部分渲染方法是一整十分简单且高效的更新网页内容的方法,在mvc程序历史想起来也非常简单!

    渲染部分视图

    绝大部分情况下mvc会把部分渲染当成其他请求一样看待,请求被路由到特定的控制器,控制器执行特定的操作逻辑代码。

    二者的区别在于请求借宿渲染视图时:通常的操作方法是使用controller.view()帮助方法返回viewresult;而部分渲染需要调用controller。Partial帮助方法来返回ParetialViewResult对象,这一点与ViewResult类似,除了PartialViewResult只渲染包含视图的内容,不会渲染外围布局。

    为了说明差别,我们来比较一下二者返回的HTML标签:普通的auction返回的视图和ajax返回的部分视图。

     

     

     

     

     部分渲染

    auctions.cshtml是在网站整体布局文件中渲染的,这也是用户在第一次查看网页时要注意的,但是,如果想重用这些布局,想让每个页面都使用同意的布局,想更新auction交易信息而无需跳转到其他页面,该怎么办

    答案就是使用partialview()方法来创建partialviewresult,取代controllerview()生成的view esult对象,代码如下:

     注意除了将view换成partialview()方法,别的都一样,partialviewresult甚至可以使用viewresult依赖的视图,事实上,partialviewresult和viewresult几乎是等价的,只有一点不同,机partialviewresult只渲染html标签内容,不包含外围布局和母版页内容。部分视图和正常的视图一样,任何语法都可以使用,而且可以完全使用mvc功能,比如html帮助类。

     使用auction。cshtml部分视图的渲染结果会如例6-2所示。

     修改以后,就可以使用下面的jquery客户端代码去加载新交易的html代码了:

     如果hzeRazor视图的外面编写情面的代码,则可以使用mvc urlhelper来裸游到auctioncontroller.auction操作,简单

    替换一下:

     部分视图简化页面复杂度

    前面的例子张氏了如何使用部分视图显示没有布局的页面这类视图通常不是全部页面,把一个完整的页面分割成不同的部分视图时非常好的简化复杂视图的有效方法。

    简化页面复杂度的最好的例子可能就是使用foeeach循环,如下代码里显示的交易信息

     看看foreach循环里的html标签,是否感觉似曾相识,这就是情面我盟用auctions。cshtml部分视图的渲染结果!

    这意味着了一声用html.partial()方法取代整段代码来渲染部分视图:

    注意,可以床底部分视图作为html。partial方法的第二个参数来渲染网页,这样可以通过auction对象集合里进行迭代渲染每个交易数据。

    正如本例所示,使用部分视图不仅可以简化视图结构,避免冗余代码吗,而且有利于维护网站的一致性。

    javascript渲染虽然渲染html的方法非常简单,高效,但是这种方式也非常浪费资源,应为有些html代码浏览器完全可以在客户端创建,而无需网络创术,一次该讲预渲染的方法之一就是只从服务端获取原始哦数据,然后在客户端动态创建html代码,直接操作dom对象。

    使用客户端渲染方法,必须具备两个条件,服务端可以产生序列化的数据,客户端知道如何把该数据转为标准的html代码。

    渲染json数据先来解决实现客户端的第一个问题,序列化ajax请求数据,在做之前,需要先确定使用什么技术。

    对象标记时互联网上一种简单,高效的数据传输格式,json对象使用两种数据结构,名值对集合以及有序值列表,正如名字的含义一样,javascript对象标记是基于javascript语言的子集,所以所有的新版都可以解析它。

    mvc提供了对原生json的支持,使用的是jsonresult操作结构对象,他可以接收可序列化的json模型对象,为了让控制器支持json格式的ajax请求,可直接使用controller.json()方法来创建包含可被序列化对象的jsonResult.

    为了在操作里使用json()帮助方法和jsonResult,需要在auctionscontroller里添加一个新的jsonauction操作方法:

    新的控制器操作方法放回的应答消息包含序列化的json格式的交易数据例如

     使用jsonRequestBehavior防止json劫持

    必须注意的是,json()方法的第二个参数是jsonRequestBehavior。allowGet,它可以通过asp.net mvc 框架来接收get方式的Http请求,然后返回json格式的数据。

    这种情况下jsonRequestBehavior.allowget的参数是必须的,应为默认情况下,mvc不允许对get方式的http请求返回json数据,这样就可以避免潜在的json劫持风险。此漏洞采用许多浏览器处理javascript<script>标记的方式,如果请求中的数据包括一个json数组,则可以导致公开敏感信息。

    虽然有点复杂,但是必须知道避免这种漏洞的方法面积不要给不可知的httpget请求返回json。因此再返回非敏感数据是asp.net mvc 框架允许通过jsonRequestBehavior.allowget设置允许这种不安全的方式返回json数据

    当需要通过json应答消息传输敏感信息时,可以通过在控制方法上添加httppostAttribute属性标记限制只让httppost方法提交请求,以避免安全漏洞。

     请求json数据

    服务端配置完毕之后,可通过发送请求来查询json数据,在客户端构建html代码了,jquery简化了这种工作。

    为了向mvc操作请求json数据,可以谁用ajax来调用特定deurl,并处理返回数据sucess函数的第一个参数(下面例子中名为result)包含返回的方序列化对象。

    下面的代码展示了使用jquery调用jsonauction控制器操作,并使用返回json数据通过.val()和.html()来操作dom对象。

     虽然这种客户端渲染方法需要更多的代码,但是他能大大简化网络传输的数据大小,还可以大大提高数据传输速度和显示ajax的效率。

    客户端模板

    虽然用这种字符串拼接方法生成客户端代码是非常高效的,但是他只能生成少量的Html标签代码,随着数据的增加,这会增加拼接html代码的复杂性,导致难以维护。

    客户端模板是非常高效的方法,可以让我盟按可维护的方式快速,高效的吧json数据转换为htmldaima1,客户端模板可以使用表达式定义可重用的节点,使用数据天聪控件元素,如果结合javascript逻辑代码则可以在模板中执行更加强大的数据处理逻辑。

    注意,客户端模板概念并不是任何官方文档的正是丁酉,所以为了使用这个方法需要依赖javascript库,虽然每个库的语法千差万别,但是基本的概念任然是相同的,javascript库会使用客户端模板变迁,并在函数里解析json数据生成html标签。

    下面的例子使用了mustache模板语法来定义客户端html标签,并且使用了mustache.js javascript库在浏览器里解析和执行客户端模板,其实,有很多模板可以供我们选择使用,但是需要仔细研究,对比它们的不同之处,选择最合适的一个来满足我们的需求。

    首先使用客户端模板语法来重写auction视图代码

    注意客户端模板的html标签代码几乎和最终的输出结果一样,事实上,唯一的区别就是客户端模板使用正式的数据库来替代表达式,这个简单的例子也像我们展示了客户端模板机制--大部分客户端模板提供了比简单html容器控件更强大的功能。

    其次就是编译客户端模板,或者把客户端模板Html转换成可执行的javascript函数。

    因为编译模板的代价最大,所以理想的办法是在保存文件以后立即编译。

    这样就可以立即使用编译后的模板,而不需要等待编译构成,大大提升了性能。

    最后,传递需要转换的数据类型给编译后的目标,已返回格式化的html数据供以后直接在dom里使用。

    看看里6-3这个例子是如何使用客户端模板的

     

     

     此例中的代码虽然看起来非常多,但是这个例子实际上还是很简单的:

    1.当加载页面时,脚本代码会从auction模板元素的内部查找客户端模板的html标签代码

    客户端模板方法开起来也许有点繁琐,但是,大部分情况下,易于维护和抵带宽小号两个有点足以抵消这些缺点,当程序使用ajax大量交互复杂的客户端html代码时,客户端模板经常是一种绝佳的解决方法。

    重用跨ahax和非ajax请求逻辑代码

    mvc模式驱动.net框架使用强大的“分离关注点”原则来确保每个组件之间的隔离性。虽然paetialauction和jsonauction控制器就是我们想要的,但如果仔细想想就会发现我们已经破坏了mvc模式的几条原则。

    正常情况下,mvc应用逻辑不应该绑定到视图中,为什么还有三个控制器操作执行相同的逻辑呢,而且唯一的区别只是返回给浏览器内容的方式不同

    例6-4 包含三种查询auction数据的auctionscontroller.cs

     响应ajax请求

    为了减少重复的逻辑代码 mvc提供了Request.isAjaxRequest()扩展方法,它可以帮助我盟屋顶当前的请求是否是ajax请求,我们可以使用这个方法来动态生成返回的数据格式。

    Request.isajaxRequest()方法相当简单,他只是通过检查请求消息的头部XRequest-With来确定是否是XMLHttpRequest,这是大部分浏览器都会自动给ajax请求添加的字段。

    如果希望.net mvc 发送ajax请求,name只需要在xmlhttpRequest的Http消息头里添加x-Requested-with即可。

    为了演示Request.isajaxRequest()的使用方法,先来合并auction和partialauction控制器,合并后的操作应该从数据上下文中查找auction实例对象,然后选择显示的方式,如果是ajax请求,则使用PartialView()方法返回PartialViewResult,否则使用view()返回ViewResult对象:

     修改完毕后,auction控制器操作就可以同时响应两种请求,Http get和ajax,代码逻辑保持不变。

    不幸的是,asp.net代码没有一共累死Reqwuest。isajaxRequest()的方法判断请求是否是json数据,但是对它稍作修改就可以轻易实现自定义逻辑。

    我们使用最简单的解决办法:在控制器操作方法里添加一个参数来指定是否返回json数据。

    例如,可以查找一个名为format的请求参数,当值为json时返回jsonReault。

     客户端可以通过在请求地址后面添加“?format=json”来请求json格式的交易数据,例如,/Auctions/Auction/1234?format=json。

    可以把一些代码一直到单独的扩展方法里,以便复用这些代码,就像Request.isAJAXrEQUEST()一样:

     使用isjsonRequest()扩展方法后,之前的代码可以简化为:

     跨控制器操作指定统一逻辑

    如果把部分视图渲染和前面介绍的判断json请求返回数据的逻辑代码放在同一个控制器操作里,就可以在同一个应用里实现返回不同结果的灵活方法,下面是优化后的auctionsController.cs;

     这些代码比较灵活,但事实上没有其他的操作可以使用Auction控制器李丁一的代码,所幸mvc提供了完美的机制在多个控制器操作上重用统一逻辑规则,操作过滤器

    把这些代码一直到操作过滤器中,就可以在其他控制器上重用这个过滤器,可以通过创建一个类继承system.web.mvc,actionfilterattribute类型,再重写onAUCTIONEXECUTED()方法来实现,这样就可以在操作执行完毕之后来修改结果,但是需要在操作结果修改之前;

     把auction控制器操作里的代码移植到新的类里后,在ajax或者json请求进来时修改操作结果:

     现在可以使用MultipleResponseFormatsAttribute操作过滤器属性标记任意操作方法,可以动态确定返回的结果类型是视图,部分视图或者json,可以根据请求消息来确定

     发送数据到服务器

    本章的前半部分关注请求内容和服务器返回的ajax数据结果,现再就要看另一半内容了;通过ajax向服务器发送请求。

    向web服务器发送请求的两种方式就是通过url查询参数和通过表单提交数据(http get和post方法)。本书第一章介绍了asp.net mvc的模型绑定,以及mvc自动从请求消息里获取控制器参数。

    除了从第一张知道查询字符串映射和普通http表单post数据之外,同归哦mvc模型绑定框架还知道如何映射json格式的数据到操作参数,这意味着操作控制器可以接受json格式的数据,不需要自己处理数据,因为mvc框架自动支持了。

    jqeury提供的$.post()方法非常简单,可以向操作控制器发送json格式数据的请求消息,只要提供url以及要发送的数据,jquery就会把对象序列化成json格式的数据,作为表单的请求数据。

     记住控制器操作并不需要做什么特别处理,json格式的数据会自动映射到操作方法的参数上,整个控制器方法要做的就是执行逻辑代码比如添加新数据到数据库以及返回结果create操作方法如下:

     提交复杂的json对象

    默认的json模型绑定逻辑包含一个重要的限制,0-1方法,这就是说,工厂期望整个应答消息只包含json格式的数据,不允许部分字段是json格式的数据,部分字段是其他格式的数据。

    现在来看一下默认方法带来的问题,假设要传递一个账单Bid对象的集合,每个对象都包含两个属性amount和timestamp

     json数组不仅更干净,跟简单,更小,而且在浏览器里更容易使用javascript构建和操作,这种简单性在动态构建表单的时候非常有用,例如允许用户一次参与多种拍卖活动。

    但是为了使用默认的的faultmodelbinder在json数据里表示账单Bids信息,还需要发送整个json独享例如:

     表面上,给模型绑定提交json对象看起来不错,其实这个方法有很多弊端。

    首相客户端必须动态构建整个消息,而且必须知道对象的每个字段。html表单不再是个窗体,而是jsvascript逻辑代码手机数据的方式

    首先服务端只会在意content type为application、json的json请求消息,所以这种方法对标准http get请求没用,只对包含正确头部消息类型的ajax请求有效,最后乳沟只有一个字段有效,在默认的绑定逻辑下,绑定器会认为整个对象无效

    为了尽量避免这些问题,可以通过子弟昂一模型板器来替换内置的json半点模型逻辑,入里6-5所示,jsonmodelbinder与json值提供这工厂不同,它允许在json数据里包含别的字段,而不轻质整个请求消息为json格式,应为模型绑定器分别不支持json数据,对发部分模型自定义绑定器来说json模型绑定器继承自defaultmodelbinder所以可以在不包含json数据是回退到模型的绑定逻辑。

     选择模型绑定器

    如果没有其他的配置asp.net mvc会为所有的模型是用defaultmodelbinder可以用过设置Modelbindeers.binders.defaultbinder属性来将新绑定器替换为默认模型绑定器。例如

    如果没有其他的配置

     代码设置完毕后皮。josmmodelbinder就会成为新的默认绑定器,并处理没有指定绑定器的所有模型。

    为模型使用自定义标记属性

    或许指定模型绑定器的最优雅方式就是使用抽象声明方式来标记类和属性,虽然可以将这种方式用于任意想要的模型,但是最好还是和请求模型绑定,应为模型绑定本省就是为请求模型而生的。

     使用jsonmodelbindeattribute标记createprodyucrtrequest,unitprize,依旧是说应该使用jsonModelBINDER(JSONmODELbINDERaTTRIBUTE。GETbINDER()创建)来绑定create-productrequest。unitoprice属性。

    这嗨哟啊在没有全局处理器或者模型办定期提供这是才是用注意前文提到的优先级。

    注册全局绑定器跟设置默认(回退)绑定器差不多,我盟也可以未单独的类型注册模型绑定器,其语法更设置默认办定期一样,非常简单,这个例子报名吗,vc框架为每个模型使用jsonmodelbinder

     这个方法可以让我们在整个程序范围内吧绑定到某个特定类型上,这也是模型绑定器数性的一种等价代码实现方式。

    高效的收发json数据

    json是构建ajax的ria(译注1)web应用的基础模块,所以了解如何正确使用json非常重要,正如下面的代码所示,jquery让这一切变得非常简单,我盟可以很方便的处理jsonhehtml元素。

    最具挑战性的问题恐怕就是json数据的序列化,复杂对象通常包含很多关系,或者依赖数据访问技术,比如ef,当使用json时,可能出现无法序列化对象的情况,这是就会返回500状态码,表达服务器内部错误。

    另外的确定就是复杂对象,javascript处理起来可能也有问题,解决这个问题的一个好经验,就是定义轻量级的实体类型,叫"数据转换对象(dto)",可方便进行类型转换,dto可以使用简单的数据结构,并且可避免复杂的层级关系。

    此外,dto类应该只包含应用或者请求需要的字段,如果有多个dto类也是可以的,甚至对同一个实体,每个不同的请求返回不同的结果。

    下面是个简单的dto类例子,简单的数据结构方便javascript进行操作,而且,由于dto的体积更小,所以它比auction模型更适合作为ajax应答消息,这也是一种很好的优化措施。

    跨域ajax请求

    默认情况下,浏览器只允许来自本站的请求,这种限制可以避免很多安全问题,比如跨站脚本攻击(xss),有时候,应用确实需要与外部托管的Rest api交互,比如twitter或者google。

    这种情况下,外部的web应用必须支持jsonp请求或者跨站资源共享 mvc不直接提供支持,要实现这种功能需一些代码和配置工作。

    jsonp巧妙地利用了跨站请求伪造技术,技术允许我盟实现ajax跨域滴哦用,不过浏览器会非常辛苦。

    宏观上看,jsonp交互包含以下几步

    1.客户端创建接收jsonp应答消息的javascript函数,比如updateauction。

    2.客户端动态为dom添加<script>标签,欺骗浏览器误以为它正在包含一个真正的及哦啊本,然后利用浏览器允许《script》引用外资占资源的后门。

    3.<script>指定外部的jsonp服务器地址,然后指定第一步里回调的函数名称,例如<script href="http://other.com/auctions/1234?callback=updateAuction"/>。

    4.服务器处理别的json请求一样处理请求,一个重要的区别就是,它不是直接在应答消息里返回json对象,而是在客户端回调函数名里包装对象(如下面例子所示)。

    注意,服务器既不知道也不关心回调函数是什么,只知道唯一的职责就是调用函数,并假定客户端一定存在这个函数。

     值得注意的是,jsonp方法是一种完全不同的c/s数据交换方法,他在回调的函数参数里包含原生的json数据,而不是直接返回json数据(正常的ajax请求)。因此在客户端访问数据的方法只有在jsonp回调函数里实现。

    上面的例子中jsonp回调函数的参数里就包含了序列化的json数据,jsonp应答消息可能在执行回调之前执行其他逻辑代码,例如在现实时间之前把格式转换为用户的当地时间:

    上面的例子中,jsonp回调函数的参数里就包含可序列化的json数据,jsonp应答消息可能在执行回调之前执行其他逻辑代码,例如,在现实时间之前把格式装换为用户的当地时间:

     

     发送jsonp请求

    jquery $.ajax方法为jsonp请求提供了完美的支持,我们要做的就是在datatype和jsonpcallback里指定jsonp的数据类型以及指定客户端回调函数的名字。

    下面的例子展示了jquery$.ajaxyJSONP请求的代码:

     注意,它是查询字符串参数,而不是使用.success()和。error()祖册时间的javascript函数,

    回调函数必须是全局的,唯一的函数,否则jsonp脚本无法执行这个回调函数。

    为asp.net mvc控制器操作添加jsonp支持

    对jsonp。asp.net mvc 并没有提供内置支持,所以要想在操作方法里使用jsonp,就要自己实现代码,新云的是,jsonp返回的结果数据比mvc框架的jsonresult操作结果更新。

    支持jsonp的最好方法也许就是创建自定义actionResult,例6-6所示为自定义实现代码。

    也许你已经注意到,jsonpResult硬编码吧jsonRequestBehavior属性设置为jsonRequestBehavior.allowget。这是因为,根据定义,所有的jsonp请求必须是get请求。

    每个jsonp请求都会存在安全漏洞,所以我盟必须避免通过jsonp发送铭感信息。

    为了应答jsonp请求,只需要返回jsonResult对象:

    启用跨站资源共享

    跨域ajax调用的首选方法是跨站资源共享(cors),与jsonp不同,cors不会利用安全漏洞,而且,它是由特殊的http消息头告诉浏览器服务允许跨域ajax调用,避免了黑客,让cors方法更加简单,应为这样就不在需要javascript回调函数或者自定义操作结果类。

    为了启用cors支持,只需要给每个需要cors支持的请求消息设置access-control-allow-origin header值即可,可以吧允许访问的域名设置成“白名单”,或者使用“*”授权访问任何域名:

     也有别的方法,如可以给网站的全部请求消息添加http消息头,只要在配置文件system.webserver>httpProtocol>customheaders节点下设置以下代码:

     接着发送普通的jquery$.ajaxy请求即可

     添加完cors的支持代码其实就是实现了一个件但,高效的ajax调用功能,但不同之处在于这个例子可以发送jsonp调用请求消息。

    对于追求完美用户体验的网站开发人员来说,知道何时以及如何shiyongajax非常重要,本章介绍了几种不同的ajax使用方法,并深入介绍了mvc框架对ajax请求地支持,同时,也介绍了jquery提供的强大api,让我盟能够轻易实现网站的ajax交互,最后还介绍了如何实现跨域ajax请求。

  • 相关阅读:
    Python学习札记(十五) 高级特性1 切片
    LeetCode Longest Substring Without Repeating Characters
    Python学习札记(十四) Function4 递归函数 & Hanoi Tower
    single number和变体
    tusen 刷题
    实验室网站
    leetcode 76. Minimum Window Substring
    leetcode 4. Median of Two Sorted Arrays
    leetcode 200. Number of Islands 、694 Number of Distinct Islands 、695. Max Area of Island 、130. Surrounded Regions 、434. Number of Islands II(lintcode) 并查集 、178. Graph Valid Tree(lintcode)
    刷题注意事项
  • 原文地址:https://www.cnblogs.com/555556J/p/13614624.html
Copyright © 2011-2022 走看看