-
10个小白也会的asp.net开发基础教程详解
一、ASP动态网页设计的含义及特点近年来,动态网页设计已成为网站开发的主流。动态网页与静态网页是相对应的,之所以叫做动态网页是因为能与后台数据库进行交互,数据传递,从而实现数据的实时更新,这是静态网页所做不到的。我们经常见到的动态网页类型为asp或者是php(当然还有其他的类型)。那么什么是ASP动态网页设计呢?下面让我们一起来看看ASP动态网页设计的含义及特点吧。更多详情,请浏览http://www.epwk.com/meijie/175102.html二、怎么配置asp动态网站开发教程_asp动态网站开发详解开发工具网络技术在不断的发展,互联网成为人们快速获取、发布和传递信息的重要渠道,它在人们政治、经济、生活等各个方面发挥着重要的作用。Internet上发布信息主要是通过网站来实现的,获取信息也是要在Internet“海洋”中按照一定的检索方式将所需要的信息从网站上下载下来。因此网站开发在Internet应用上的地位显而易见,它已成为政府、企事业单位信息化建设中的重要组成部分,从而倍受人们的重视。ASP的技术特点是:1、可使用服务器端的脚本来产生客户端的脚本。2、无须compile编译,容易编写,可在服务器端直接执行。3、使用普通的文本编辑器,如Windows的记事本,即可进行编辑设计。4、ActiveXServerComponents(ActiveX服务器组件)具有无限可扩充性。可以使用VisualBasic、Java、VisualC++、COBOL等程序设计语言来编写你所需要的ActiveXServerComponent。更多详情,请浏览http://gonglue.epwk.com/31227.html三、ASP、PHP、JSP三者间有什么本质区别ASP,PHP,JSP作为主流的开发语言,都占有较大的市场份额。但是很多人都不清楚ASP、PHP、JSP三者之间具有怎样的区别。至于怎么去选择合适的开发语言,大家自然就比较的困惑了。而作为开发者的我们都希望找到一款适合自己的网站开发语言,那么如何去选择,又有哪些依据呢?下面从ASP、PHP、JSP三者的优点和缺点出发进行比较分析。更多详情,请浏览http://gonglue.epwk.com/32078.html四、ASP在动态网站开发的优势ASP作为动态网站开发的利器,已经被得到广泛的应用。那么,ASP在实际动态网站中的应用又是如何,又有哪些明显的优势呢?相信大家都没有进行详细的总结过,小编为大家仔细的总结了一下,ASP在动态网站开发的优势,希望对大家有所帮助。更多详情,请浏览http://gonglue.epwk.com/32175.html五、详细介绍ASP网站开发技术人们只是知道ASP开发技术用途广泛,对于什么是ASP网站开发技术,ASP开发技术有哪些特点,总是说不出个所以然来。这也是想学习ASP技术的人所迷惑的,为了大家更加清楚地认识ASP技术,小编为大家做如下介绍。更多详情,请浏览http://gonglue.epwk.com/32185.html六、asp动态网页设计建设_asp网页设计常用语句每一个网站都是由许多页面构成的,整站网页设计也分为动态网页设计和静态网页设计。网页(WebPages或WebDocuments)即是笼统经过IE等浏览器看到的网站文件,网页是网站的根蒂根蒂组成单元,它是网站具体模式(如翰墨、图片、视频等)的载体,需求经过不同的网页存储各类百般的模式。网页既笼统直接存储在网站的根目录下,也笼统存储在径自的子文件夹中。网页一样也有网址,假设网页是存储在网站的根目录下,那末它的网址技俩为“网站网址,首页作为一个径自的网页,它相等于网站的出口。作为网站的起始点,首页汇总了网站主要栏目标链接,经过这些链接笼统接见网站的方方面面。更多详情,请浏览http://gonglue.epwk.com/32388.html七、ASP动态网站开发教程建立自己的网站平台身边的同事朋友们都把注意转移到了网络上,开始了网络上的发展,都建立了自己的网站成立了自己的网站平台,使他们的公司得到了不错的发展,没有想到网络现在已经这样走进了我们的生活,为了公司的发展和事业的进步,我也不能被世界淘汰要跟上时代的步伐,决定建立自己的网站,经过询问原来他们都用的ASP网站开发教程。更多详情,请浏览http://gonglue.epwk.com/32704.html八、ASP动态网站开发程序原代码竞争力强的原因社会的网络话成为了现在社会的必然,学习网站开发建设也成为了现代人不可缺少的技能,不管国营企业还是私营单位基本上都有了自己的网络平台,我们也在使用着不同的网站建设软件,来满足我们的需求,建立自己的网站扩大自己的知名度,是自己的公司企业得到更多人的认识和了解,当我在为用什么网站建设软件发愁时了解到了ASP动态开发软件,ASP网站开发软件取得了与众不同的效果,让我们来了解一下这个软件吧。更多详情,请浏览http://gonglue.epwk.com/32705.html九、如何学习ASP动态网站开发的应用中心网站的建设不再是那些高端的IT认识的专利的,因为网络的普及使我们再难离开,网络融进了我们的生活,网站的建设也不再那么的高不可攀,现在的网站运用到了各个行业里,在那里都能看到他的身影,这也使他的需求大大增加,网站开发学习也成为了我们在社会进行竞争的一大条件。对于网站的建设有着太多的软件开发工具,了解发现ASP动态网站有着巨大的特点。更多详情,请浏览http://gonglue.epwk.com/32706.html十、ASP.NET3.5网站开发技术入门书籍我大学的时候是学网站开发专业的,为了学好这个专业,为了毕业后能靠这个专业养活自己。大学时,我认真钻研,苦读了不少网站开发的书籍,从中学到了很多知识。网站开发的书籍有很多,但是有一本书,书名是《新手学ASP.NET3.5网络开发》,这本书让我从中受益匪浅,现在想把这本书和大家一起分享。更多详情,请浏览http://gonglue.epwk.com/32874.html以上就是本文的全部内容,更多详情,请浏览http://www.epwk.com/special/apjcjc/
-
ASP.NET MVC5高级编程 之 模型
1.为MVCMusicStore建模Models文件夹(右击)-->添加-->类为类添加对应的属性:1publicclassAlbum2{3publicvirtualintAlbumId{get;set;}4publicvirtualintGenreId{get;set;}5publicvirtualintArtistId{get;set;}6publicvirtualstringTitle{get;set;}7publicvirtualdecimalPrice{get;set;}8publicvirtualstringAlbumArtUrl{get;set;}9publicvirtualGenreGenre{get;set;}10publicvirtualArtistArtist{get;set;}11}类Genre:1publicclassGenre2{3publicvirtualintGenreId{get;set;}4publicvirtualstringName{get;set;}get;set;}6publicvirtualListAlbums{get;set;}7}类Artist:1publicclassArtist2{3publicvirtualintArtistId{get;set;}4publicvirtualstringName{get;set;}5}注意:此处的属性都是virtual构建完类之后,需要对整个项目进行编译。2.基架ASP.NETMVC中的基架可以为应用程序的创建、读取、更新和删除(CRUB)功能生成所需要的样板代码。基架模版检测模型类的定义,然后生成控制器以及与该控制器关联的视图,有些情况下还会生成数据访问类。基架知道如何命名控制器、命名视图以及每个组件需要执行什么代码,也知道在应用程序中如何放置这些项以使应用程序正常工作。2.1基架选项:像MVC框架的所有其他项一样,如果不喜欢默认的基架,就可以根据自己的需要自定义基架或替换现有基架的代码生成机制。也可以通过NuGet(搜索scaffolding)查找可替代的基架模版。2.2常用的基架模版:(1)MVC5Controller——Empty该会向Controllers文件夹中添加一个具有指定名称且派生自Controller的类(控制器)。这个控制器带有的唯一操作就是Index操作,且在内部除了返回一个默认ViewResult实例的代码之外,没有其他任何代码。这个模版不会生成任何视图。(2)MVC5Controllerwithread/writeActions该模版会向项目中添加一个带有Index、Details、Create、Edit和Delete操作的控制器。虽然控制器内部的操作不是完全空白,但不会执行任何有实际意义的操作,除非向其中添加自己的代码并为他们创建试图。(3)WebAPI2APIControllerScaffolders有几个模版向项目中添加一个继承自基类ApiController的控制器。可以使用这些模版为应用程序创建WebAPI(4)MVC5ControllerwithViews,UsingEntityFramework该模版不仅生成了带有整套Index、Details、Create、Edit和Delete操作的控制器及其需要的所有相关视图,并且还生成了与数据库交互(持久保存数据到数据库或从数据库中读取数据)的代码。2.3基架和实体框架:新建的ASP.NETMVC5项目会自动包含对实体框架(EF)的引用。EF是一个对象关系映射(object-relationalmapping,ORM)框架,它不但知道如何在关系型数据库中保存.NET对象,而且还可以利用LINQ查询语句检索那些保存在关系型数据库中的.net对象。EF支持数据库优先、模型优先和代码优先的开发风格;MVC基架采用代码优先代码优先的风格。代码优先是指可以在不创建数据库模式、也不打开VisulaStudio设计器的情况下,向SQLServer中存储或检索信息。模型对象中的属性如果设置为虚拟的,可以给EF提供一个指向C#类集的钩子(hook),并未EF启用了一些特性,如高效的修改跟踪机制(efficientchangetrackingmechanism)。EF需要知道模型属性值的修改时刻,因为需要在这一刻生成并执行一个SQLUPDATE语句,使这些改变和数据库保持一致。2.4DbContext类当使用EF的代码优先方法时,需要使用从EF的DbContext类派生出的一个类来访问数据库。该派生类具有一个或多个DbSet类型的属性,类型DbSet中的每一个T代表一个想要持久保存的对象。可以把DbSet想象成一个特殊的、可以感知数据的泛型列表,它知道如何在父上下文中加载和保存数据。例如,下面的类(数据上下文类)就可以用来存储和检索Albums、Artist和Genre的信息:1publicclassMusicStoreDB:DbContext2{3publicMusicStoreDB():base("name=MusicStoreDB")4{5}67publicSystem.Data.Entity.DbSetAlbums{get;set;}89publicSystem.Data.Entity.DbSetArtists{get;set;}1011publicSystem.Data.Entity.DbSetGenres{get;set;}1213}使用先前的数据上下文,可以通过使用Linq查询,按字母顺序检索出所有专辑,代码如下:1vardb=newMusicStoreDB();2varallAlbums=fromalbumindb.Albums3orderbyalbum.Titleascending4selectalbum;3.执行基架模版(1)右击Controllers文件夹-->添加-->控制器(2)添加基架-->包含视图的MVC5控制器(使用EF)-->添加(3)在“添加控制器”对话框中,选择模型类、数据上下文类,修改控制器名称。(4)修改数据上下文类,修改为MvcMusicStoreDB:数据上下文会根据选择的模型,自动生成数据上下文类,如下所示。1publicclassMusicStoreDB:DbContext2{3publicMusicStoreDB():base("name=MusicStoreDB")4{5}67publicSystem.Data.Entity.DbSetAlbums{get;set;}89publicSystem.Data.Entity.DbSetArtists{get;set;}1011publicSystem.Data.Entity.DbSetGenres{get;set;}1213}注意MusicStoreDB():base("name=MusicStoreDB")中,MusicStoreDB是配置的数据库连接1246如果不配置具体的连接,EF将尝试连接SQLServer的LocalDB实例,并且查找与DbContext派生类名相同的数据库。如果EF能够连接上数据库服务器,但找不到数据库,那么框架会自动创建一个数据库。(5)视图一旦基架运行完成,就将在新的视图文件夹Views/Album中出现一个视图集。视图提供了罗列、编辑和删除专辑的功能。4.执行基架代码4.1用实体框架创建数据库4.2使用数据库初始化器保持数据库和模型变化同步的一个简单方法是允许实体框架重新创建一个现有的数据库。可以告知EF在应用程序每次启动时重新创建数据库或者仅当检测到模型变化时重建数据库。当调用EF的Database类中的静态方法SetInitializer时,可以选择这两种策略中的任意一个。框架中带有两个IDatabaseInitializer对象:DropCreateDatabaseAlways和DropCreateDatabaseIfModelChanges。可以根据这两个类的名称来辨别每个类所代表的策略。两个初始化器都需要一个泛型类型的参数,并且这个参数必须是DbContext的派生类。在文件global.asax.cs中,可以在应用程序启动过程中设置一个初始化器:源代码:1protectedvoidApplication_Start()2{3Database.SetInitializer(newMusicStoreDbInitializer());45AreaRegistration.RegisterAllAreas();6FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);7RouteConfig.RegisterRoutes(RouteTable.Routes);8BundleConfig.RegisterBundles(BundleTable.Bundles);9}修改为:1protectedvoidApplication_Start()2{3Database.SetInitializer(newDropCreateDatabaseAlways());45AreaRegistration.RegisterAllAreas();6FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);7RouteConfig.RegisterRoutes(RouteTable.Routes);8BundleConfig.RegisterBundles(BundleTable.Bundles);9}4.3播种数据库Seed方法可以为应用程序创建一些初始化的数据。1protectedvoidApplication_Start()2{3Database.SetInitializer(newMusicStoreDbInitializer());45AreaRegistration.RegisterAllAreas();6FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);7RouteConfig.RegisterRoutes(RouteTable.Routes);8BundleConfig.RegisterBundles(BundleTable.Bundles);9}播种数据:1publicclassMusicStoreDbInitializer2:System.Data.Entity.DropCreateDatabaseAlways3{4protectedoverridevoidSeed(MusicStoreDBcontext)5{6context.Artists.Add(newArtist{Name="AlDiMeola"});7context.Genres.Add(newGenre{Name="Jazz"});8context.Albums.Add(newAlbum9{10Artist=newArtist{Name="Rush"},11Genre=newGenre{Name="Rock"},12Price=9.99m,13Title="Caravan"14});15base.Seed(context);16}17}这样,每次重新生成音乐商店数据库时,都会有两种流派(Jazz和Rock)、两个艺术家(AlDiMeola和Rush)和一个专辑。代码会在程序启动时注册这个初始化器。5编辑专辑5.1创建编辑专辑的资源默认的MVC路由规则是将HTTPGET请求中的/StoreManager/Edit/5传递到StoreManager控制器的Edit操作中,代码如下:1publicActionResultEdit(int?id)2{3if(id==null)4{5returnnewHttpStatusCodeResult(HttpStatusCode.BadRequest);6}7Albumalbum=db.Albums.Find(id);8if(album==null)9{10returnHttpNotFound();11}12ViewBag.ArtistId=newSelectList(db.Artists,"ArtistId","Name",album.ArtistId);13ViewBag.GenreId=newSelectList(db.Genres,"GenreId","Name",album.GenreId);14returnView(album);15}下面是商店管理器的Edit视图中用来为流派创建下拉列表的代码:12@Html.LabelFor(model=>model.GenreId,"GenreId",new{@class="control-labelcol-md-2"})34@Html.DropDownList("GenreId",String.Empty)5@Html.ValidationMessageFor(model=>model.GenreId)67在视图中使用DropDownList辅助方法,Edit中的两行代码就是为了构建从数据库中所有可得到的流派和艺术家的列表,并将这些列表存储在ViewBag中以方便以后让DropDownList辅助方法检索。ViewBag.GenreId=newSelectList(db.Genres,"GenreId","Name",album.GenreId);第1个参数指定了将要放在列表中的项第2个参数是一个属性名称,该属性包含当用户选择一个指定项时使用的值(键值,像52或2)第3个参数是每一项要显示的文本第4个参数包含了最初选定项的值5.2模型和视图模型终极版针对专辑的编辑情形,模型对象(Album对象)并没有包含编辑专辑视图所需要的全部信息,因为另外还需要所有可能的流派和艺术家列表。针对这种问题,有两种解决方案。基架生成代码展示了第一种解决方案:将额外的信息传递到ViewBag结构中。这个方案完全合理而且还便于实现。第二种解决方案:强类型模型,创建一个视图特定模型的对象,将专辑信息、流派和艺术家信息传递给一个视图。这个模型可能如下定义:1publicclassAlbumEditViewModel2{3publicAlbumAlbumToEdit{get;set;}4publicSelectListGenres{get;set;}5publicSelectListArtists{get;set;}6}这样Edit操作就不需要将信息放进ViewBag,而需要实例化AlbumEditViewModel类,设置所有的对象属性,并将视图模型传递给视图。5.3Edit视图当用户单击页面上的Save按钮时,HTML将发送一个HTTPPOST请求,请求回到/StoreManager/Edit/1页面。这时浏览器会自动收集用户在表单输入中的所有信息并将这些值(及其相关的name属性值)放在请求中一起发送。这里注意input和select元素的name属性,需要和Album模型中的属性匹配。5.4响应编辑时的POST请求接受HTTPPOST请求来编辑信息的操作的名称也是Edit,但不同于前面看到的Edit操作,因为它有一个HttpPost操作选择器特性:1[HttpPost]2[ValidateAntiForgeryToken]3publicActionResultEdit([Bind(Include="AlbumId,GenreId,ArtistId,Title,Price,AlbumArtUrl")]Albumalbum)4{5if(ModelState.IsValid)6{7db.Entry(album).State=EntityState.Modified;8db.SaveChanges();9returnRedirectToAction("Index");10}11ViewBag.ArtistId=newSelectList(db.Artists,"ArtistId","Name",album.ArtistId);12ViewBag.GenreId=newSelectList(db.Genres,"GenreId","Name",album.GenreId);13returnView(album);14}这个操作的作用就是接收含有用户所有编辑项的Album模型对象,并将这个对象保存到数据库中。(1)编辑happypathhappypath就是当模型处于有效状态并可以将对象保存到数据库时执行的代码路径。操作通过Model.IsValid属性来检查模型对象的有效性。这个属性可以看作一个信号,来确保用户输入有用的专辑特性值。如果模型处于有效状态,则执行以下的代码:db.Entry(album).State=EntityState.Modified;这行代码告知数据上下文该对象在数据库中已经存在,所以框架应该对现有的专辑应用数据库中的值而不要再创建一个新的专辑记录。db.SaveChanges();上下文生成一条SQLUPDATE命令更新对应的字段值以保留新值。(2)编辑sadpathsadpath就是当模型无效时操作采用的路径。在sadpath中,控制器操作需要重新创建Edit视图,以便用户更改自身产生的错误
-
ASP.NET MVC5高级编程 之 视图
1.1理解视图约定当创建一个项目模版时,可以注意到,项目以一种非常具体的方式包含了一个结构化的Views目录。在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其对应。这就提供了视图与操作方法关联的基础。1publicActionResultIndex()2{3returnView();4}视图选择逻辑在/Views/ControllerName目录(这里就是去掉Controller后缀的控制器名)下查找与操作方法同名的视图。此处选择的是/Views/Home/Index.cshtml。与ASP.NETMVC中的大部分方法一样,这一约定是可以重写的。想让Index操作方法渲染一个不同的视图,可以向其提供一个不同的视图名称,代码如下:1publicActionResultIndex()2{3returnView("NotIndex");4}对于上面的编码,操作方法依然在/Views/Home目录中查找视图,但选择的不再是Index.cshtml,而是NotIndex.cshtml。如果需要制定完全位于不同目录结构中的视图,编码如下:1publicActionResultIndex()2{3returnView("~/Views/Example/Index.cshtml");4}1.2强类型视图假设需要编写一个显示Album实例列表的视图,一种方法是将专辑添加到ViewBag中,然后在视图中进行迭代。1publicActionResultList()2{3varalbums=newList();4for(inti=0;i<10;i++)5{6albums.Add(newAlbum{Title="Product"+i});7}8ViewBag.Albums=albums;9returnView();10}然后,再在视图中迭代显示,如下代码:12@foreach(Albumain(ViewBag.AlbumsasIEnumerable))3{4@a.Tilte5}6注意在枚举之前需要将动态的ViewBag.Albums转换为IEnumerable类型。为了使代码整洁,可以使用dynamic关键字,但是当访问每个Album对象的属性时,就不能再使用智能感知功能。12@foreach(dynamicpinViewBag.Albums)3{4@p.Tilte5}6强类型视图既能获得dynamic的简洁语法,又能获得强类型和编译时检查的好处(比如正确的输入属性和方法名称)。强类型视图允许设置视图的模型类型。因此可以从控制器向视图传递一个在两端都是强类型的模型对象,从而获得智能感知、编译器检查等好处。在Controller方法中,可以通过向重载的View方法中传递模型实例来指定模型,代码如下:1publicActionResultList()2{3varMusics=newList();4for(inti=0;i<10;i++)5{6Musics.Add(newMusicModels{MusicName="MusicName"+i.ToString()});7}8returnView(Musics);9}下一步是告知视图哪种类型的模型正在使用@model声明。但要注意这里需要输入模型类型的完全限定类型名(名称空间和类型名称),如下所示1@modelIEnumerable23@foreach(MvcMusicStore.Models.MusicModelsmusicinModel)4@music.SingerName5如果不想输入模型类型的完全限定类型名,可使用@using关键字,如下所示1@usingMvcMusicStore.Models2@modelIEnumerable34@foreach(MusicModelsmusicinModel)5@music.SingerName当创建一个包含数据条目表单的视图(如Edit视图或者Create视图)时,选择这个选项会添加对jqueryval捆绑的脚本引用。如果要实现客户端验证,那么这些库就是必须的。除这种情况外,完全可以忽略这个复选框。创建一个分部视图:选择这个意味着要创建的视图不是一个完整的视图,因此,Layout选项是不可选用的。生成的部分视图除了在其顶部没有标签和标签外,很像一个常规的视图。使用布局页:这个选项决定了要创建的视图是否引用布局,还是成为一个完全独立的视图。如果选择使用默认的布局,就没必要指定一个布局了,因为在_ViewStart.cshtml文件中已经指定了布局。这个选项是用来重写默认布局文件的。2.2Razor视图引擎ASP.NETMVC中提供了两种不同的视图引擎:较新的Razor视图引擎和较早的WebForms视图引擎。Razor中的核心转换字符是(@),这个单一字符用作标记-代码的转换字符,有时也反过来用作代码-标记的转换字符。这里一共有两种基本类型的转换:代码表达式和代码快。Listing@items.Lengthitems.表达式@items.Length是作为隐式表达式来求解的,然后输出表达式的值3。这里不需要指出代码表达式的结束位置。但是Razor自动从代码转回标记的能力,也带来了二义性的问题:1@{2stringrootNamespace="MyApp";3}4@rootNamespace.Models这个示例想要的输出结果是:MyApp.Models,然而实际会出现错误,提示string没有Models属性,此时需要通过圆括号解决:1@{2stringrootNamespace="MyApp";3}4@(rootNamespace).Models这样可以告诉Razor,.Models是字面量文本,而不是代码表达式的一部分。对于电子邮件地址时的情况,Razor可以辨别出邮件的模式,进而不处理这种形式的表达式:support@megacorp.com但是如果确实想将这种形式的字符串作为一个表达式,也需要合理用圆括号:对于Item_@item.Length期望的输出结果是Item_3,但是Razor会将其按照字符串进行打印。处理的方法是:Item_@(item.Length)有时也需要使用@符号来进行转义:12Youshouldfollow3@@aspnet43.Razor语法示例常见用途下的Razor语法;隐式代码表达式代码表达式将被计算并将值写入到响应中,这就是视图中显示值的一般原理。@model.Message显示代码表达式代码表达式的值将被计算并写入到响应中,这就是在视图中显示值的一般原理1+2=@(1+2)无编码代码表达式有些情况下,需要显式的渲染一些不应该采用HTML编码的值,这时可以采用Html.Raw方法来保证该值不被编码@Html.Raw(model.Message)代码块不像代码表达式先求的表达式的值,然后再输出到响应,代码块是简单地执行代码部分1@{2intx=123;3stringy="because."4}文本和标记相结合这个例子显示了在Razor中混用文本和标记的概念,具体如下:1@foreach(variteminitems)2{3Item@item.Name.4}混合代码和纯文本Razor查找标签的开始位置以确定何时将代码转换为标记。然而,有时可能想在一个代码块之后立即输出纯文本。例如,在下面的这个例子中就是展示如何在一个条件语句块中显示纯文本1@if(showMessage)2{3thisisplaintext4}或者1@if(showMessage)2{3@:thisisplaintext.4}第一种使用标签,这样只是把标签内容写入到响应中,而标签本身则不写入。第二种方式使用一种特殊的语法,实现代码到纯文本的转换,但是这种方法每次只能作用于一行文本。转义代码分隔符可使用“@@”来编码“@”以达到显示“@”的目的。此外,时钟都可以选择使用HTML编码来实现。Razor:theasp.nettwitterhandleis@aspnet或者theasp.nettwitterhandleis@@aspnet代码注释1@*2代码块3*@4.布局Razor的布局有助于使应用程序的多个视图保持一致的外观。可以使用布局为网站定义公共模版(或只是其中的一部分)。公公模版包含一个或多个占位符,应用程序中的其他视图为它们提供内容。从某些角度看,布局很像视图的抽象基类。如下则是一个简单的布局:1DOCTYPEhtml>234@ViewBag.Title567@ViewBag.Title8@RenderBody()9@RenderSection("Footer")1011对应视图的代码如下:1@{2Layout="~Views/Shared/SiteLayout.cshtml";3ViewBag.Title="TheIndex";4}56thisisthemaincontent!78@sectionFooter{9thisisthefooter.10}@section语法为布局中定义的一个节指定了内容。默认情况下,视图必须为布局中定义的每一个节提供内容。如果向当前的布局中添加一个新节时,会使得引用该布局的每一个视图都不能正常运行。但是,RenderSection方法有一个重载版本,允许指定不需要的节。可以给required参数传递一个false值来标记Footer节是可选的。@RenderSection("Footer",required:false)有时也在视图中定义一些默认内容12@if(IsSectionDefined("Footer"))3{4RenderSection("Footer");5}6else7{8thisisthedefaultfooter9}105.ViewStart在创建一个默认的ASP.NETMVC项目后,会在Views目录下自动添加一个_ViewStart.cshtml文件,它指定了一个默认布局1@{2Layout="~/Views/Shared/_Layout.cshtml"3}如果多个视图都使用都使用同一个布局,就会产生冗余。_ViewStart.cshtml中的代码先于任何视图运行,所以一个视图可以重写Layout属性的默认值,从而重新选择了一个不同的布局。如果一组视图拥有共同的设置,那么_ViewStart.cshtml中的代码可以用来对共同的视图进行统一配置。如果有视图需要覆盖统一的设置,只需要修改对应的属性值即可。6.指定部分视图除了返回视图之外,操作方法也可以通过PartialView方法以PartialViewResult的形式返回部分视图:1publicclassHomeController:HomeController2{3publicActionResultMessage()4{5ViewBag.Message="thisisapartialview.";6returnPartialView();7}8}这种情形下,渲染的是视图Message.cshtml,但是如果布局是由_ViewStart.cshtml页面指定(而不是直接在视图中)的,将无法渲染布局。除了不能指定布局之外,部分视图看起来和正常视图没有分别:@ViewBag.Message在使用Ajax技术进行更新时,部分视图是很有用的。示例使用jQuery将一个部分视图的内容加载到一个使用了Ajax调用的当前视图中:1>4$(function(){5$('#result').load('/home/message');6});>8}代码使用jQuery的load方法向Message操作方法发出一个Ajax请求,而后使用请求的结果更新id属性值为result的DIV元素。
-
ASP.NET MVC5高级编程 之 路由
每个ASP.NETMVC应用程序都需要路由来定义自己处理请求的方式。路由是MVC应用程序的入口点。路由的核心工作是将一个请求映射到一个操作路由主要有两种用途:匹配传入的请求(该请求不匹配服务器文件系统中的文件),并把这些请求映射到控制器操作。构造传出的URL,用来响应控制器操作1.特性路由1.1路由URL创建一个ASP.NETMVCWeb应用程序项目后,浏览Global.asax.cs文件中的代码中,Application_Start方法中调用了一个名为RegisterRoutes的方法。该方法是集中控制路由的地方,包含在~/App_Start/RouteConfig.cs文件中。1publicstaticvoidRegisterRoutes(RouteCollectionroutes)2{3routes.IgnoreRoute("{resource}.axd/{*pathInfo}");45routes.MapRoute(6name:"Default",7url:"{controller}/{action}/{id}",8defaults:new{controller="Home",action="Index",id=UrlParameter.Optional}9);12}修改RegisterRoutes方法中的内容,只通过调用MapMvcAttributeRoutes注册方式让RegisterRoutes方法启用特性路由。修改后的方法如下:1publicstaticvoidRegisterRoutes(RouteCollectionroutes)2{3routes.MapMvcAttributeRoutes();4}路由的核心工作是将一个请求映射到一个操作。完成这项工作最简单的方法是在一个操作方法上直接使用一个特性://响应URL为/about的请求1publicclassHomeController:Controller2{3[Route("about")]4publicActionResultAbout()5{6returnView();7}8}每当收到URL为/about的请求时,这个路由特性就会运行About方法。MVC收到URL,然后运行代码。如果对于操作有多个URL,就可以使用多个路由特性。例如,想让首页可以通过/、/home和/home/index这几个URL都能访问,可以设置路由如下://响应URL为/、/home和/home/index三个URL1[Route("")]2[Route("home")]3[Route("home/index")]4publicActionResultIndex()5{6returnView();7}传入路由特性的字符串叫做路由模版,他就是一个模式匹配规则,决定了这个路由是否是用于传入的请求。如果匹配,MVC就运行路由的操作方法。1.2路由值对于简单的路由,适合刚才的静态路由,但并不是每个URL都是静态的。例如,如果操作显示个人记录的详情,则需要在URL中包含记录的ID。通过添加路由参数可解决这个问题://id作为一个动态参数1[Route("Person/{id}")]2publicActionResultDetails(intid)3{4returnView();5}通过花括号的id,就可以作为一个占位符。多个占位符的情况可如下标识://具有多个占位符1[Route("{year}/{month}/{day}")]2publicActionResultIndex(stringyear,stringmonth,stringday)3{4returnView();5}1.3控制器路由之前的讨论了如何把路由特性直接添加到操作方法上,但是很多时候,控制器类中的方法遵循的模式具有相似的路由模版,以HomeController控制器为例:1publicclassHomeController:Controller2{3[Route("home/index")]4publicActionResultIndex()5{6returnView();7}8[Route("home/about")]9publicActionResultAbout()10{11returnView();12}13[Route("home/contact")]14publicActionResultContact()15{16returnView();17}18}除了URL的最后一段,这些路由是相同的。所以期望能有一个方法能映射到home下的一个URL。1[Route("home/{action}")]2publicclassHomeController:Controller3{4publicActionResultIndex()5{6returnView();7}8publicActionResultAbout()9{10returnView();11}12publicActionResultContact()13{14returnView();15}16}使用控制器类的一个特性代替每个方法上的所有路由特性。在控制器类上定义路由时,可以使用一个叫做action的特殊路由参数,它可以作为任意操作名称的占位符。action参数的作用相当于每个操作方法上单独添加路由,并静态输入操作名:它只是一种更加方便的语法而已。有时控制器上的某些具有与其他操作稍微不同的路由。此时,我们可以把最通用的路由放到控制器上,然后在具有不同路由模式的操作上重写默认路由。例如,如果我们认为/home/index过于冗长,但是又想支持/home,就可以如下:1[Route("home/{action}")]2publicclassHomeController:Controller3{4[Route("home")]5[Route("home/index")]6publicActionResultIndex()7{8returnView();9}10publicActionResultAbout()11{12returnView();13}14publicActionResultContact()15{16returnView();17}18}在操作方法级别指定路由特性时,会覆盖控制器级别指定的任何路由特性。在前面的例子中,如果Index方法只有第一个路由特性(home),那么尽管控制器有一个默认路由home/{action},也不能通过home/index来访问Index方法。如果需要定义某个操作的路由,并且仍希望应用默认的控制器路由,就需要在操作上再次列出控制器的路由。前面的类仍然带有重复性。每个路由都以home/开头(毕竟,类的名称是HomeController)。通过使用RoutePrefix,可以仅在一个地方指定路由以home/开头:1[RoutePrefix("home")]2[Route("{action}")]3publicclassHomeController:Controller4{5[Route("")]6[Route("index")]7publicActionResultIndex()8{9returnView();10}11publicActionResultAbout()12{13returnView();14}15publicActionResultContact()16{17returnView();18}19}现在,所有的路由特性都可以省略home/,因为前缀会自动加上home/。这个前缀只是一个默认值,必要时可以覆盖该行为。例如,除了支持/home和/home/index以外,我们还想让HomeController支持/。为此,使用~/作为路由模版的开头,路由前缀就会被忽略。在下面的代码中,HomeController的Index方法支持全部三种URL(/、/home和/home/index)://支持URL为/、/home和/home/index1[RoutePrefix("home")]2[Route("{action}")]3publicclassHomeController:Controller4{5[Route("~/")]6[Route("")]//此处也可以简写[Route]7[Route("index")]8publicActionResultIndex()9{10returnView();11}12publicActionResultAbout()13{14returnView();15}16publicActionResultContact()17{18returnView();19}20}1.4路由约束因为方法参数的名称正好位于由路由特性及路由参数名称的下方,所以很容易忽视这两种参数的区别。1[Route("person/{id}")]2publicActionResultDetails(intid)3{4returnView();5}对于这种情况,当收到/person/bob这个URL的请求时,根据路由规则,会将bob作为id参数传入,但bob无法转换为int类型,所以方法不能执行。如果想同时支持/person/bob和/person/1,并且每个URL运行不同的操作,可以尝试添加具有不同特性路由的方法重载,如下所示:1[Route("person/{id:int}")]2publicActionResultDetails(intid)3{4returnView();5}6[Route("person/{name}")]7publicActionResultDetails(stringname)8{9returnView();10}因为传入的参数存在二义性,1也可以解释为字符串,因此需要添加int约束。路由约束是一种条件,只有满足该条件时,路由才能匹配。这种约束叫做内联约束。内联路由约束为控制路由何时匹配提供了精细的控制。如果URL看上去相似,但是具有不同的行为,就可以使用路有约束来表达这些URL之间的区别,并把它们映射到正确的操作。1.5路由的默认值1[Route("home/{action}")]2publicclassHomeController:Controller3{4publicActionIndex()5{6returnView();7}8}对于以上代码,如果通过URL为:/home进行访问,根据类定义的路由模版home/{action},以上代码不能运行。因为定义的路由只匹配包含两个段的URL,但是/home只包含一个段。如果我们想让Index成为默认的action,路由API允许为参数提供默认值,代码如下:[Route("home/{action=Index}")]{action=Index}这段代码为{action}参数定义了默认值。此时,该默认情况就允许路由匹配没有action参数的请求。也就是现在既可以匹配具有一个段的URL,也可以匹配具有两个段的URL。[Route("home/{action=Index}/{id?}")]这段代码提供默认值Index,以及可选值id。因为第二个段id是可选值,因此匹配的URL不再必须包含两个段。2.传统路由在~/App_Start/RouteConfig.cs文件中存在方法RegisterRoutes,在方法中添加传统路由,代码如下:1publicstaticvoidRegisterRoutes(RouteCollectionroutes)2{3routes.MapRoute("simple","{first}/{second}/{third}");4}MapRoute方法的最简单形式是采用路由名称和路由模版。与特性路由一样,路由模版是一种模式匹配规则,用来决定该路由是否应该处理传入的请求(基于请求的URL决定)。特性路由与传统路由之间最大的区别在于如何将路由链接到操作方法。传统路由依赖于名称字符串而不是特性来完成这种链接。在操作方法上使用特性路由时,不需要任何参数,路由就可以工作。路由特性被直接放到了操作方法上,当路由匹配时,MVC知道去运行该操作方法。将特性路由放到控制器类上时,MVC知道使用哪个类(因为该类上有路由特性),但是不知道运行哪个方法,所以我们使用特殊的action参数来通过名称指明要运行的方法。如果针对上面的简单路由请求一个URL(例如a/b/c),回收到一个500错误。因为传统路由不会自动链接控制器或操作。要指定操作,需要使用action参数(就像在控制器类上使用路由特性时所做的那样)。要指定控制器,需要使用一个新参数controller。如果不定义这些参数,MVC不会知道想要运行的操作方法,所以会通过返回一个500错误。通过修改简单路由,使其包含这些必需参数,可以解决这个问题:routes.MapRoute("simple","{controller}/{action}");现在,如果请求一个URL,如/home/index,MVC会认为这是在请求一个名为home的{controller}和一个名为index的{action}。根据约定,MVC会把后缀Controller添加到{controller}路由参数的值上,并尝试定位具有该名称(区分大小写)并实现了System.Web.Mvc.IController接口的类型。注:特性路由直接绑定到方法和控制器,而不是仅指定名称,这意味着他们更加精确。例如,使用特性路由时,可以随意命名控制器类,只要以Controller后缀结尾即可(名称不需要与URL相关)。在操作方法上直接使用特性,意味着MVC知道运行哪个重载版本,并不需要在同名的多个操作方法中选择。2.1路由值controller和action参数很特殊,因为他们映射到控制器和操作的名称,是必须参数。但是这两个参数并不是可以使用的全部参数。更新路由来包含第三个参数:routes.MapRoute("simple","{controller}/{action}/{id}");对于/albums/display/123的请求,会导致实例化MVC的类,调用其中的Display方法,同时将123传递给Display方法的参数id。routes.MapRoute("simple","site/{controller}/{action}/{id}");上面的路由指出请求URL的第一段只有以site开头,才能与请求相匹配。因此,上面的路由可以匹配/site/albums/display/123,而不能匹配/albums/display/123。此外,还有更灵活的路由语法规则:在路径段中允许字面值和路由参数混合在一起。它仅有的限制就是不允许有两个连续的路由参数1//有效2{language}-{country}/{controller}/{action}3{controller}.{action}.{id}4//无效5{controller}{action}/{id}只需要记住,除非路由提供了controller和action参数,否则MVC不知道URL运行哪些代码。2.2路由默认值特性路由通过将参数{id}内联修改为{id?},使得id成为可选的参数。传统路由则是将信息放到路由模版后面的单独一个参数中:1routes.MapRoute("simple","{controller}/{action}/{id}",2new{id=UrlPatameter.Optional});第三个参数用于默认值{id=UrlPatameter.Optional},这段代码为{id}参数定义了默认值。下面的代码为action指明默认值:1routes.MapRoute("simple",2"{controller}/{action}/{id}",3new{id=UrlPatameter.Optional,action="index"});2.3路由约束传统路由允许使用正则表达式来限制路由是否匹配请求。而在特性路由中,使用类似于{id:int}的语法在路由模版中内联指定约束,具体代码如下:1routes.MapRoute("blog","{year}/{month}/{day}",2new{controller="blog",action="index"},3//路由约束4new{year=@"d{4}",month=@"d{2}",day=@"d{2}"});注:路由机制会自动的使用"^"和“$”符号包装指定的约束表达式。换言之,此处可以匹配参数“1234”,但不匹配“adc1234def”,也不能匹配“/08/05/25”。3.选择特性路由还是传统路由选择传统路由:想要集中配置所有路由使用自定义约束对象存在现有可工作的应用对象,而又不想修改应用程序选择特性路由:想把路由与操作代码保存在一起创建新应用程序,或者对现有应用程序进行巨大修改传统路由的集中配置意味着可以在一个地方理解请求如何映射到操作。传统路由也比特性路由更灵活。例如,向传统路由添加自定义约束对象很容易。C#中的特性只支持特定类型的参数,对于特性路由,这意味着只能在路由模版字符串中指定约束。特性路由很好的把关于控制器的所有内容放到了一起,包括控制器使用的URL和运行的操作。4.URL生成详解开发人员调用像Html.ActionLink或Url.Action之类的方法,这些方法反过来再调用RouteCollection.GetVirtualPath方法,并向它传递一个ResponseContext对象、一个包含值的字典以及用来选择生成URL的路由名称(可选参数)。路由机制查看要求的路由参数(即没有提供路由参数对默认值),并确保提供的路由值字典为每一个要求的参数提供一个值。否则URL生成程序会立即停止,并返回空值。一些路有可能包含没有对应路由参数的默认值。例如,路有可能为category键提供默认值“pastries”,但是category不是路有URL的一个参数。这种情况下,如果用户传入的路由值字典为category提供了一个值,那么该值必须匹配category的默认值。然后路由系统应用路有的约束,如果有的话。路由匹配成功!现在可以通过查看每一个路由参数,并尝试利用字典中的对应值填充相应参数,进而生成URL
-
ASP.NET MVC5高级编程 之 Ajax
jQuery不仅支持所有现代浏览器,包括IE、Firefox、Safari、Opera和Chrome等,还可以在编写代码和浏览器API冲突时隐藏不一致性(和错误)。1.jQueryjQuery擅长在HTML文档中查找、遍历和操纵HTML元素。一旦找到元素,jQuery就可以方便的在其上进行操作,如连接事件处理程序、使其具有动画效果以及围绕它的Ajax交互等。1.1jQuery函数jQuery函数对象可以用来访问jQuery特性。1$(function(){2$("#album-listimg").mouseover(function(){3$(this).animate({height:'+=25',width:'+=25'})4.animate({height:'-=25',width:'-=25'});5});:$(this).animate({height:'+=25',width:'+=25'}).animate({height:'-=25',width:'-=25'});上面的例子实现了在触发mouseover事件时,匹配选择器的img元素会产生动画效果。在上面的代码中,之所以使用this关键字来引用要做动画效果的元素,是因为this是指向的是触发事件的元素。注意代码第一次将元素传递给jQuery函数的方法($(this))。jQuery将该参数看成一个元素的引用参数,并返回一个包含有该元素的封装集。一旦将某个元素包含在jQuery封装集中,就可以调用jQuery方法(如animate)来操纵这个元素。示例中的代码首先将图像放大,然后在缩小的效果。1.2jQuery选择器选择器是指传递给jQuery函数的,用来在DOM中选择元素的字符串。例子意义$("#header")查找id值为“header”的元素$(".editor-label")查找class名为“.editor-label的所有元素”$("div")查找所有元素$("#headerdiv")查找id值为“header”元素的所有后代元素$("#header>div")查找id值为“header”元素的所有子元素$("a:even")查找编号为偶数的锚标签“#album-listimg”用来选择id为album-list的标签。作为选择器的字符串看起来像层叠样式表(CascadingStyleSheet,CSS)中的项,是因为jQuery选择器的语法派生自CSS3.0选择器的语法,并在其基础上做了一些补充。1.3jQuery事件jQuery的另一个优势在于,它提供了用来订阅DOM中事件的API。尽管使用一个通用的on方法可以捕获指定名称的任何事件,但jQuery也为一般的事件提供了专门的方法,比如click、blur和submit。可以通过传进一个函数来告知jQuery在事件触发时进行的处理。传递进的函数可以是匿名的,也可以是一个作为事件处理程序的命名函数,如下所示:1$("#album-listimg").mouseover(function(){2animateElement($(this));3});45functionanimateElement(element){6element.animate({height:'+=25',width:'+=25'})7.animate({height:'-=25',width:'-=25'});8});9}一旦选择了一些DOM元素或是在一个事件处理程序内,jQuery就可以很容易的操纵页面上的元素,读取或设置他们的特性值,添加或移除他们的CSS类等。下面的代码演示了当用户的鼠标移过元素时,如何向一个页面上的锚标签添加或从中删除highlight类。当用户在标签上移动鼠标时,锚标签就会改变外观(假如有一个合适的highlight样式设置):1$("a").mouseover(function(){2$(this).addClass("highlight");3}).mouseout(function(){4$(this).removeClass("highlight");5})注意:代码中用到的所有依赖于封装集的jQuery方法,像mouseover方法,都返回同样的jQuery封装集。这就是说可以继续在选择的元素上调用jQuery方法,而不用再重新选择这些元素。这称为方法链。许多常用操作在jQuery中都有与其对应的捷径方法(shortcut)。设置mouseover和mouseout效果是一种常见的操作,切换样式类型也是一种常见的操作。可以使用jQuery捷径方法重写上面的代码:1$("a").hover(function(){2$(this).toggleClass("highlight");标签。"上面的调用将渲染/App_Start/BundleConfig.cs中预定义的“jquery”脚本捆绑,这种捆绑利用了ASP.NET中的捆绑和微小特性,该特性利用版本号中包含的通配符匹配,自动优先使用jQuery的轻量版本。1publicstaticvoidRegisterBundles(BundleCollectionbundles)2{"~/bundles/jquery").Include("));56//......1$(function(){2$("#album-listimg").mouseover(function(){3$(this).animate({height:'+=25',width:'+=25'})4.animate({height:'-=25',width:'-=25'});5});"Modernizr.js:通过改造老版本浏览器来帮助我们构建富有现代气息的应用程序。其中一个重要工作就是在老版本浏览器中启动新的HTML5元素(比如header、nav和menu),也可以检测特定浏览器是否支持一些高级功能,像定位位置(geolocation)和绘画画布(drawingcanvas)。3Ajax3.1Ajax辅助方法ASP.NETMVC框架中包含一组Ajax辅助方法,他们可以用来创建表单和指向控制器操作的链接,但不同的是它们是异步进行的。当然使用这些辅助方法时,不需要编写任何脚本代码来实现程序的异步性。这些Ajax辅助方法依赖于非侵入式MVC的jQuery扩展,如果使用这些辅助方法,需要引入脚本文件jquery.unobtrusive-ajax.js,并在视图中添加此脚本引用。3.2在项目中添加非侵入式Ajax脚本Nuget-->MicrosoftjQueryUnobtrusiveAjax-->安装脚本引用可以添加到程序的_Layout视图中,也可以仅添加到使用Ajax辅助方法的视图中。除非在网站中发出大量的Ajax请求,否则建议添加到单独的视图中。脚本的添加可以拖拽。3.3Ajax的ActionLink方法与HTML辅助方法类似,Ajax属性上的大部分Ajax辅助方法都是扩展方法(出了AjaxHelper类型之外)。Ajax属性的ActionLink方法可创建一个具有异步行为的锚标签,代码实现:12@Ajax.ActionLink("Clickheretoseetoday'sspecial!",3"DailyDeal",4null,5newAjaxOptions6{7UpdateTargetId="dailydeal",8InsertionMode=InsertionMode.Replace,9HttpMethod="GET"10},11new{@class="btnbtn-primary"})12ActionLink第一个参数指定了链接文本;第二个参数是要异步调用的操作的名称,类似于同名的HTML辅助方法,Ajax辅助方法ActionLink也提供了各种重载版本,用来传递控制器的名称、路由值和HTML特性。AjaxOptions参数指定了发送请求和处理服务器返回的结果的方式。参数中还包括用来处理错误、显示加载元素、显示确认对话框等的选项。在这个示例中,AjaxOptions参数的选项指定了要使用来自服务器的响应元素来替换id值为“dailydeal”的元素最后的htmlAttributes参数指定了为链接使用的HTML类,以应用一个基本的Bootstrap按钮样式。为得到服务器的响应,需要在控制器的HomeController上添加一个DailyDeal操作:1publicActionResultDailyDeal()2{3varalbum=GetDailyDeal();45returnPartialView("_DailyDeal",album);6}78privateAlbumGetDailyDeal()9{10varalbum=storeDB.Albums11.OrderBy(a=>System.Guid.NewGuid())12.First();13album.Price*=0.5m;14returnalbum;1$(function)(){2$("a[data-ajax]=true").//dosomething3});这段代码将使用jQuery查找data-ajax特性值为true的所有锚元素。元素上的data-ajax特性用来标识该元素需要实现异步行为。一旦非侵入式脚本识别了异步元素,它就可以读取该元素的其他设置(像替换模式、更新目标以及HTTP方法),还可以通过使用jQuery连接事件和发送请求来修改该元素的行为。所有ASP.NETMVCAjax特性都使用data-特性。3.4Ajax表单使用Ajax在页面上放置一个异步表单12Artistsearch34@using(Ajax.BeginForm("ArtistSearch","Home",5newAjaxOptions6{7InsertionMode=InsertionMode.Replace,8HttpMethod="GET",9OnFailure="searchFailed",10LoadingElementId="ajax-loader",11UpdateTargetId="searchresults",12}))13{14151619}2021221functionsearchFailed(){2$("#searchresults").html("Sorry,therewasaproblemwiththesearch.");3}如果服务器返回一个错误,就意味着Ajax辅助方法执行失败,此时可以捕获OnFailure事件。最后,当用户单击提交按钮提交表单时,服务器会收到一个Ajax请求,并可能以任意格式的内容做出响应。当客户端收到来自服务器端的响应时,非侵入式脚本就会将相应内容放入DOM中。此处,新内容要替换的是一个id值为searchresults的元素。控制器中的代码为:1publicActionResultArtistSearch(stringq)2{3varartists=GetArtists(q);45returnPartialView("_ArtistSearch",artists);6}78privateListGetArtists(stringsearchString)9{10returnstoreDB.Artists11.Where(a=>a.Name.Contains(searchString))12.ToList();13}渲染的部分视图利用模型构建列表。该部分视图的名称是ArtistSearch.cshtml,位于项目的Views/Home文件夹下。1@modelIEnumerable2345@foreach(variteminModel)6{7@item.Name8}9104客户端验证对于数据注解特性来说,ASP.NETMVC框架的客户端验证是默认开启的,下面介绍Album类的Title和Price属性:1[Required]2[StringLength(160,MinimumLength=2)]34publicstringTitle{get;set;}56[Required]7[Range(0.01,100.00)]89[DataType(DataType.Currency)]4.2自定义验证编写的MaxWordsAttribute验证特性代码如下:1publicclsaaMaxWordsAttribute:ValidationAttribute2{3publicMaxWordsAttribute(intmaxWords):base("{0}hastoomanywords.")4{5_maxWords=maxWords;6}78protectedoverrideValidationResultIsValid(objectvalue,9ValidationContextvalidationContext)10{11varvalueAsString=value.ToString();12if(valueAsString.Split('').Length>_maxWords)13{14varerrorMessage=FormatErrorMessage(validationContext.DisplayName);15returnnewValidationResult(errorMessage);16}17returnValidationResult.Success;18}19privatereadonlyint_maxWords;20}该特性只支持服务器端的验证,使用方法如下:1[MaxWords(10)]2publicstringTitle{get;set;}4.2.1IClientValidatableIClientValidatable接口定义了单个方法:GetIClientValidationRules。当ASP.NETMVC框架使用这个接口查找验证对象时,它会调用GetClientValidationRules方法来检索ModelClientValidationRule对象序列。这些对象携带有框架发送给客户端的元数据和规则。可使用下面的代码为自定义验证器实现该接口:1publicclsaaMaxWordsAttribute:ValidationAttribute,IClientValidatable2{3publicMaxWordsAttribute(intmaxWords):base("{0}hastoomanywords.")4{5_maxWords=maxWords;6}7publicintWowrdCount{get;set;}8protectedoverrideValidationResultIsValid(objectvalue,ValidationContextvalidationContext)9{10varvalueAsString=value.ToString();11if(valueAsString.Split('').Length>_maxWords)12{13varerrorMessage=FormatErrorMessage(validationContext.DisplayName);14returnnewValidationResult(errorMessage);15}16returnValidationResult.Success;17}1819publicIEnumerableGetClientValidationRules(MdelMetadatametadata,ControllerContextcontext)20{21varrule=newModelClientValidationRule();22rule.ErrorMessage=FormatErrorMessage(metadata.GetDisplayName());23rule.ValidationParameters.Add("wordcount",WordCount);24rule.ValidationType="maxwords";25yieldreturnrule;26}这些信息就是嗲吗放进返回规则中的内容。请注意,如果需要在客户端触发多种类型的验证,代码可以返回多个规则。ASP.NETMVC框架在客户端上利用GetClientValidationRules方法返回的规则将信息序列化为data-特性。
-
ASP.NET MVC5入门1之项目创建
1.创建项目文件-->新建-->项目VisualC#-->Web-->ASP.NETWeb应用程序MVC此时处于选中状态,勾选“添加单元测试”(可选择)。完成以上步骤,基本的项目创建完成,此时点击“F5”可运行项目,如下图所示。(为方便标识,此后用url代替“localhost:20391”)MVC代表:模型-视图-控制器。Models:标识该应用程序的数据并使用验证逻辑来强制实施业务规则的数据类Views:应用程序动态生成HTML所使用的模版文件Controllers:处理浏览器的请求,取得数据模型,然后指定要响应浏览器请求的视图模版2.添加一个控制器类(右击)Controllers文件夹-->添加-->控制器选择“MVC5控制器-空”为控制器添加名称添加后在Controllers文件夹中会多出文件“MvcMusicStoreController.cs”,并且在文件夹Views下会多出“MvcMusicStore”文件夹目录结构如下所示:修改控制器“MvcMusicStoreController.cs”文件中的代码为:1publicclassMvcMusicStoreController:Controller2{3publicstringIndex()4{5return"Thisismydefaultaction";6}78publicstringWelcome()9{10return"ThisisWelcomeactionmethod...";11}12}此时重新运行程序,地址栏输入“url/MvcMusicStore”3.数据路由ASP.NETMVC会调用不同的控制器类(和其内部不同的操作方法)这取决于传入URL。所使用的ASP.NETMVC的默认URL路由逻辑使用这样的格式来判定哪些代码以便调用:可在App_Start/RouteConfig.cs文件内通过配置URL路由解析规则:1publicclassRouteConfig2{3publicstaticvoidRegisterRoutes(RouteCollectionroutes)4{5routes.IgnoreRoute("{resource}.axd/{*pathInfo}");67routes.MapRoute(8name:"Default",9url:"{controller}/{action}/{id}",10defaults:new{controller="Home",action="Index",id=UrlParameter.Optional}11);12}13}如果运行程序且不提供任何URL段,默认为“Home”的控制器和Index的操作方法,在上面的代码中的defaults部分指定:第一部分的URL确定哪个控制器类会被执行。因此/MvcMusicStore映射到MvcMusicStoreController控制器类第二部分的URL确定要执行控制器类中的那个操作方法。因此/HelloWorld/Index,会使得MvcMusicStoreController控制器类的Index方法被执行。请注意,只需要浏览/MvcMusicStore路径,默认情况下会调用Index方法。如果没有明确的指定操作方法,Index方法会默认的被控制器类调用。第三部分的URL段(Parameters参数)是路由数据浏览url/MvcMusicStore/Welcome。Welcome方法会被运行并返回字符串“thisisthewelcomeactionmethod...”。默认的MVC映射为/[Controller]/[ActionName]/[Parameter]对于这个URL,控制器类是MvcMusicStore,操作方法是Welcome,此处并未用到[Parameters]部分。此处对Welcome方法进行修改,并使用了C#语言的可选参数功能,numTimes参数在不传值时,默认值为1。1publicstringWelcome(stringname,intnumTimes=1)2{3//return"ThisisWelcomeactionmethod...";4returnHttpUtility.HtmlEncode("Hello"+name+",NumTimesis:"+numTimes);5}此时运行应用程序并浏览次URL(url/MvcMusicStore/Welcome?name=Long&numtimes=4)上面的例子,没有用到URL段参数的部分(Parameters)。通过querystrings传递name和numTimes的参数用下面的代码替换“Welcome”的方法:1publicstringWelcome(stringname,intID=1)2{3//return"ThisisWelcomeactionmethod...";4//returnHttpUtility.HtmlEncode("Hello"+name+",NumTimesis:"+numTimes);5returnHttpUtility.HtmlEncode("Hello"+name+",ID:"+ID);6}这次URL第三部分的参数匹配了参数ID。4.添加一个视图控制器的默认程序是:1publicActionResultIndex()2{3returnView();4}上面的Index方法使用一个视图模版来生成一个HTML返回给浏览器。控制器的方法(也被称为actionmethod(操作方法)),如上面的Index方法,一般返回一个ActionResult(或从ActionResult所继承的类型),而不是原始的类型,如字符串。如果想使用控制器中默认的Index方法,则需要在对应的Views中添加视图文件。在Views/MvcMusicStore-->添加-->“MVC5ViewPagewith(LayoutRazor)”在指定项名称中,输入“Index”“选择布局页(selectlayoutpage)”-->"_Layout.cshtml"-->"确定",然后在解决方案资源管理器中看到View/MvcMusicStore/Index.cshtml文件。在Index.cshtml文件中添加以下代码1@{2ViewBag.Title="Index";3}45Index67HellofromourViewTemplate!运行并调试程序,得到界面:5.修改视图和布局页首先,想要修改页面顶部的链接“Applicationname”。这段文字是每个页面的公用文字,即使这段文字出现在每个页面上,但是实际上它仅保存在工程里的一个地方。在解决方案资源管理器里找到Views/Shared文件夹,打开_Layout.cshtml文件。此文件称为布局页面(Layoutpage),并且其他所有的子页面,都共享使用这个布局页面。6.将数据从控制器传递给视图控制器响应请求来的URL。控制器类是写代码来处理传入请求的地方,并从数据库中检索数据,并最终决定什么类型的返回结果会发送回浏览器。视图模版可以被控制器用来产生格式化过的HTML从而返回给浏览器。控制器负责给任何数据或者对象提供一个必须的视图模版,用这个视图模版来Render返回给浏览器的HTML。最佳的做法是:一个视图模版应该永远不会执行业务逻辑或者直接和数据库进行交互。相应的,一个视图模版应该只和控制器所提供的数据进行交互。维持这种“隔离关系”。1publicActionResultIndex()2{3returnView("NotIndex");4}对于这样的编码,操作方法依然在/Views/Home目录中查找视图,但选择的不再是Index.cshtml,而是NotIndex.cshtml。如果需要制定完全位于不同目录结构中的视图,编码如下:1publicActionResultIndex()2{3returnView("~/Views/Example/Index.cshtml");4}7.添加一个模型EntityFramework(通常称为EF)是支持代码优先(CodeFirst)的开发模式。代码优先允许通过编写简单的类来创建对象模型。在解决方案资源管理器,(右键单击)模型文件夹-->添加-->类输入类名“MusicStore”,并为类添加属性:1publicclassMusicStore2{3publicintID{get;set;}4publicstringSongName{get;set;}5publicstringSingerName{get;set;}6publicDateTimePublishDate{get;set;}7publicdecimalPrice{get;set;}8}类中的每一个属性对应表中的每一列。在这个类中,添加下面的MusicStoreDBContext类:1usingSystem.Data.Entity;23publicclassMusicStoreDBContext:DbContext4{5publicDbSetMovies{get;set;}6}MusicStoreDBContext类代表EntityFramework的音乐数据库类,这个类负责在数据库中获取、存储、更新、处理MusicStore类的实例。MusicStoreDBContext继承自EntityFramework的DbContext基类。8.SQLServerExpressLocalDBLocalDB是一个SQLServerExpress轻量级版本的数据库引擎。它在用户模式下启动、执行。LocalDB运行在一个特殊的SQLServerExpress的执行模式,即允许能够使用MDF文件数据库。通常情况下,LocalDB的数据库文件都保存在web项目的App_Data文件夹下面。注:在生产环境的Web应用程序中,不推荐使用SQLServerExpress。尤其是LocalDB不应该用于Web应用程序的生产环境,因为它没有被设计要使用IIS,但是LocalDB的数据库能很容易的迁移到SQLServer或SQLAzure。打开应用程序根目录的Web.config文件找到数据库的连接设置代码:124做如下修改:12459.从控制器访问数据模型注:进行该步骤之前,应先编译程序,这样才可以使用之前的模型类及上下文类。Controllers文件夹-->新增-->Controller-->选择控制器设置模型类、数据上下文类并设置控制器名称。完成以上步骤,VisualStudio会创建以下文件和文件夹:控制器文件夹中的MusicStoreController.cs文件项目视图文件夹下的MusicStore文件夹在新的Views/MusicStore文件夹中创建Create.cshtml、Delete.cshtml、Details.cshtml、Edit.cshtml和Index.cshtml文件。运行程序,url输入“url/MusicStore”
-
ASP.NET MVC之基架
参考ASP.NETMVC5高级编程(第5版)定义:通过对话框生成视图及控制器的模版,这个过程叫做“基架”。基架可以为应用程序的创建、读取、更新和删除(CRUB)功能生成所需的样板代码。基架模版检测模型类的定义,然后生成控制器以及与该控制器关联的视图,有些情况下还会生成数据访问类。基架知道如何命名控制器、命名视图以及每个组件需要执行什么代码,也知道在应用程序中如何放置这些项以使应用程序正常工作。基架选项:如果不喜欢默认的基架,可以根据需要自定义基架或替换现有基架的代码生成机制。也可以通过NuGet(搜索scaffolding)查找可替代的基架模版。NuGet库中全是运用特定设计模式和技术来生成代码的基架。常用的基架模版:(1)MVC5Controller——Empty该会向Controllers文件夹中添加一个具有指定名称且派生自Controller的类(控制器)。这个控制器带有的唯一操作就是Index操作,且在内部除了返回一个默认ViewResult实例的代码之外,没有其他任何代码。这个模版不会生成任何视图。(2)MVC5Controllerwithread/writeActions该模版会向项目中添加一个带有Index、Details、Create、Edit和Delete操作的控制器。虽然控制器内部的操作不是完全空白,但不会执行任何有实际意义的操作,除非向其中添加自己的代码并为他们创建试图。(3)WebAPI2APIControllerScaffolders有几个模版向项目中添加一个继承自基类ApiController的控制器。可以使用这些模版为应用程序创建WebAPI(4)MVC5ControllerwithViews,UsingEntityFramework该模版不仅生成了带有整套Index、Details、Create、Edit和Delete操作的控制器及其需要的所有相关视图,并且还生成了与数据库交互(持久保存数据到数据库或从数据库中读取数据)的代码。基架和实体框架:新建的ASP.NETMVC5项目会自动包含对实体框架(EF)的引用。EF是一个对象关系映射(object-relationalmapping,ORM)框架,它不但知道如何在关系型数据库中保存.NET对象,而且还可以利用LINQ查询语句检索那些保存在关系型数据库中的.net对象EF支持数据库优先、模型优先和代码优先的开发风格;MVC基架采用代码优先代码优先的风格。代码优先是指可以在不创建数据库模式、也不打开VisulaStudio设计器的情况下,向SQLServer中存储或检索信息。模型对象中的属性如果设置为虚拟的,可以给EF提供一个指向C#类集的钩子(hook),并未EF启用了一些特性,如高效的修改跟踪机制(efficientchangetrackingmechanism)。EF需要知道模型属性值的修改时刻,因为需要在这一刻生成并执行一个SQLUPDATE语句,使这些改变和数据库保持一致。
-
ASP.NET MVC5高级编程 之 HTML辅助方法
Html属性调用HTML辅助方法,Url属性调用URL辅助方法,Ajax属性调用Ajax辅助方法。HTML辅助方法1.Html.BeginForm1@using(Html.BeginForm("Search","Home",FormMethod.Get))2{345}等效的html:设置元素的class特性就要求匿名类型对象上必须有一个名为class的属性,或者值的字典中有一个名为class的键。在字典中有一个“class”的键值不是问题,问题在于对象中带有一个名为class的属性。因为class是c#语言的保留关键字,不能用作属性名称或标识符,所以必须在class前面加一个@符号作为前缀:@using(Html.BeginForm("Search","Home",FormMethod.Get,new{target="_blank",@class="editForm"}))另一个问题是将属性设置为带有连字符的名称(项data-val)。带有连字符的C#属性名是无效的,但所有的HTML辅助方法在渲染HTML时会将属性名中的下划线转换为连字符。1@using(Html.BeginForm("Search","Home",FormMethod.Get,new{target="_blank",@class="editForm",data_validatable=true}))等效的HTML为:2.Html.ValidationSummary1@Html.ValidationSummary(true)用来显示ModelState字典中所有验证错误的无序列表。使用布尔类型参数(值为true)来告知辅助方法排除属性级别的错误,而不显示那些具体模型属性相关的错误3.Html.TextBox1@Html.TextBox("Title",Model.Title)渲染一个type特性为text的input标签,用于接收用户自由形式的输入,等效的HTML:14.Html.TextArea1@Html.TextArea("text","helloworld")等效HTML:1hello
world5.Html.Label1@Html.LabelFor("GenereId")等效HTML:Genre返回一个元素,并使用String类型的参数来决定渲染的文本和for特性值6.Html.DropDownList和Html.ListBoxDropDownList允许进行单项选择,而ListBox支持多项选择(在要渲染的标记中,把multiple特性的值设置为multiple)通常,select元素有两个作用:展示可选项的列表展示字段的当前值下拉列表需要包含所有可选项的SelectListItem对象集合,其中每一个SelectListItem对象又包含有Text、Value和Selected三个属性。可以根据需要构建自己的SelectListItem对象集合,也可以使用框架中的SelectList或者MultiSelectList辅助方法类来构建。这些类可以查看任意类型的Ienumerable对象并将其转换为SelectListItem对象的序列。例如,StoreManager控制器中的Edit操作:1publicActionResultEdit(intid)2{3varalbum=storeDB.Albums.Single(a=>a.AlbumId==id);4ViewBag.Genres=newSelectList(storeDB.Genres.OrderBy(g=>g.Name),"GenreId","Name",album.GenreId);5returnView(album);6}这里控制器操作不仅构建了主要模型(用于编辑的模型),还构建了下拉列表辅助方法所需要的表示模型。SelectList构造函数的参数指定了原始集合(数据库中的Genres表)、作为后台值使用属性名称(Name)以及当前所选项的值(他决定将哪一项标记为选择项)。如果想在避免反射开销的同时还想自己生成SelectListItem集合,可以使用LINQ的select方法来将SelectListItem对象集放入项目Genres:1varalbum=MusicStoreDB.Genres2.OrderBy(g=>g.Name)3.AsEnumerable()4.select(g=>newSelectListItem5{6Text=g.Name,7Value=g.GenreId.ToString(),8Selected=album.GenreId==g.GenreId9});10returnView(album);7.Html.ValidationMessage1@Html.ValidationMessage("Title")等效HTML:12Whataterriblename!3当ModelState字典中的某一特定字段出现错误时,可以使用ValidationMessage辅助方法来显示相应的错误提示消息。8.Html.Hidden1@Html.Hidden("WizardStep","1")方法用于渲染隐藏的输入元素,等效HTML:强类型方法是Html.HiddenFor。如果模型有一个WizardStep属性,就可以这样使用:@Html.HiddenFor(m=>m.WizardStep)9.Html.Password1@Html.Password("UserPassword")方法用于渲染密码字段。它除了不保留提交值,显示密码掩码之外,基本与TextBox辅助方法一样。等效HTML:Html.Password的强类型方法是Html.PasswordFor。下面的代码展示如何使用它来显示UserPassword属性:@Html.PasswordFor(m=>m.UserPassword)10.Html.RadioButton1@Html.RadioButton("color","red")单选按钮一般都组合一起使用,为用户的单项选择提供一组可选项。等效的HTML:Html.RadioButton有一个强类型的对应方法Html.RadioButtonFor。强类型方法不使用名称和值,而是用表达式来标识那些包含有要渲染属性的对象,当用户选择单选按钮时,后面会跟要提交的值:@Html.RadioButtonFor(m=>m.GenreId,"1")Rock11.Html.CheckBox@Html.CheckBox("IsDiscounted")方法是唯一一个渲染两个输入元素的辅助方法,等效HTML:12 辅助方法、模型和视图数据:辅助方法如Html.TextBox和Html.DropDownList(以及其他所有表单辅助方法)检查ViewData对象以获得要显示的当前值(在ViewBag对象中的所有值也可以通过ViewData得到)。(1)如果想在一个表单中设置专辑的价格,可使用下面的控制器代码1publicActionResultEdit(intid)2{3ViewBag.Price=10.0;4returnView();5}在相应的视图中,使用ViewBag中的值来为TextBox辅助方法命名,可以实现渲染显示价格的文本框:@Html.TextBox("Price")TextBox辅助方法将生成如下所示的HTML标记: (2)当辅助方法查看ViewData里面的内容时,他们也能看到其中的对象属性。修改先前的控制器操作:1publicActionResultEdit(intid)2{3ViewBag.Album=newAlbum{Price=11};4returnView();5}在响应的视图中,可以使用下面这行代码来显示一个带有专辑价格的文本框:@Html.TextBox("Album.Price")现在渲染出的HTML标记如下所示:如果在ViewData中没有匹配“Album.Price”的值,那么辅助方法将尝试查找与第一个点之前那部分名称(Album)匹配的值。换言之,就是找一个Album类型的对象。然后,辅助方法估测名称中剩余的部分(Price),并找到相应的值。注意渲染得到的input元素的id特性值使用下划线代替了点(但name特性依然使用点)。(3)TextBox辅助方法依靠强类型视图数据也能很好的工作。1publicActionResultEdit(intid)2{3varalbum=newAlbum{Price=12.0m};4returnView(album);5}视图中的代码:@Html.TextBox("Price");对应的HTML标记:(4)如果想避免自动的查找数据,可向表单辅助方法提供一个显式的值。有时,显式提供值的方法是必须的。返回到刚才正在构建(用来编辑专辑信息)的表单。控制器代码:1publicActionResultEdit(intid)2{3varalbum=storeDB.Albums.Single(a=>a.AlbumId==id);45ViewBag.Genres=newSelectList(storeDB.Genres.OrderBy(g=>g.Name)6,"GenreId"7,"Name"8,album.GenreId);910returnView(album);11}视图:@Html.TextBox("Title",Model.Title)强类型的辅助方法如果不适应使用字符串字面值从视图数据中提取值的话,也可以使用MVC提供的各种强类型辅助方法。使用强类型辅助方法时,只需要为其传递一个lambda表达式来指定要渲染的模型属性。表达式的模型类型必须和为视图指定的模型类型(使用@model指令)一致。对于专辑模型的强类型视图,需要在视图顶部输入如下所示的代码:@modelMvcMusicStore.Models.Album一旦添加模型指令,就可以使用下面的代码重写前面的专辑编辑表单:1@using(Html.BeginForm())2{3@Html.ValidationSummary(excludePropertyErrors:true)45EditAlbum67@Html.LabelFor(m=>m.GenreId)8@Html.DropDownListFor(m=>m.GenreId,ViewBag.GenresSelectList)91011@Html.TextBoxFor(m=>m.Title)12@Html.ValidationMessageFor(m=>m.Title)131415>16}注意:这些强类型的辅助方法名称除了有"For"后缀之外,跟先前使用的辅助方法还有相同的名称。尽管该代码生成了与先前代码同样的HTML标记,但是用lambda表达式代替字符串还有许多其他好处,其中包括智能感知、编译时检查和轻松的代码重构。这里不需要显式的为Title文本框设置值,这主要是因为lambda表达式向辅助方法提供了足够的信息,使其能直接读取模型的Title属性来获取需要的值。模版辅助方法ASP.NETMVC中的模版辅助方法利用元数据和模版构建HTML。其中元数据包括关于模型值(它的名称和类型)的信息和(通过数据注解或自定义提供器添加的)模型元数据。模型辅助方法有Html.Display和Html.Editor,以及分别与他们对应的强类型方法Html.DisplayFor和Html.EditorFor,还有它们对应的完整模型Html.DisplayForModel和Html.EditorForModel。@Html.TextBox("Title",Model.Title)等同于:@Html.EditorFor(m=>m.Title)两者生成的HTML标记是相同的,,但是EditorFor方法可以通过使用数据注解来改变生成的HTML渲染辅助方法12.Html.ActionLink和Html.RouteLinkActionLink辅助方法能渲染一个超链接(锚标签),渲染的链接指向另一个控制器操作,与前面看到的BeginForm辅助方法一样,ActionLink辅助方法在后台使用路由API来生成URL。当链接的操作所在控制器与用来渲染当前视图的控制器一样时,只需要指定操作的名称:1@Html.ActionLink("LinkText","AnotherAction")这里假设采用默认路由,那么执行这段代码将生成如下所示的HTML标记:1LinkText当需要一个指向不同控制器操作的链接时,可通过ActionLink方法的第三个参数来指定控制器名称。例如要链接到ShoppingCartController控制器的Index操作,可以使用下面的代码:1@Html.ActionLink("LinkText","Index","ShoppingCart")13URL辅助方法URL辅助方法与HTML的ActionLink和RouteLink辅助方法类似,但它不是以HTML标记的形式返回构建的URL,而是以字符串的形式返回这些URL。对此,有三个辅助方法:ActionContentRouteUrlAction辅助方法与ActionLink非常类似,但是它不返回锚标签。例如,下面的代码会显示浏览商店里所有Jazz专辑的URL(不是链接):12@Url.Action("Browse","Store",new{genre="Jazz"},null)3将会生成如下所示的HTML标记:12/Store/Browse?genre=Jazz314Html.Partial和Html.RenderPartialPartial辅助方法用于将部分视图渲染成字符串,如下将渲染一个名为AlbumDisplay的部分视图@Html.Partial("AlbumDisplay")RenderPartial辅助方法与Partial非常相似,但RenderPartial不是返回字符串,而是直接写入响应输出流。基于这个原因,必须将RenderPartial放入代码块中,而不能放在代码表达式。1@{Html.RenderPartial("AlbumDisplay");}2或3@Html.Partial("AlbumDisplay")一般情况下,因为Partial相对于RenderPartial来说更方便(不必使用花括号将调用封装在代码块中),所以选择Partial。然而,RenderPartial拥有较好的性能,因为它是直接写入响应流的,但这种性能优势需要大量的使用(高的网站流量或在循环中重复调用)才能看出来。15Html.Action和Html.RenderActionAction和RenderAction之间仅有的不同之处在于:RenderAction可以直接写入响应流。 -
ASP.NET MVC5高级编程 之 数据注解和验证
客户端验证逻辑会对用户向表单输入的数据给出一个即时反馈。而之所以需要服务器端验证,是因为来自网络的信息都是不能被信任的。当在ASP.NETMVC设计模式上下文中谈论验证时,主要关注的是验证模型的值数据注解特性定义在名称空间System.ComponentModel.DataAnnotations中,它们提供了服务器端验证的功能。当在模型的属性上使用这些属性时,框架也支持客户端验证。在名称空间DataAnnotations中,有4个特性可以用来应对一般的验证场合。1.1Required因为客户的名字是必须的,所以需要在模型类的属性上添加Required特性1[Required]2publicstringFirstName{get;set;}当属性是null或空时,Required特性将会引发一个验证错误。1.2StringLength校验数据的长度1[Required]2[StringLength(160)]3publicstringFirstName{get;set;}当数据长度超过160则会提醒。MinimumLength参数是一个可选项,用于设定字符串的最小长度,如下(长度>=3且_maxWords)16{17varerrorMessage=FormatErrorMessage(validationContext.DisplayName);18returnnewValidationResult(errorMessage);19}20returnValidationResult.Success;21}22privatereadonlyint_maxWords;23}24}FormatErrorMessage可以使用合适的错误提示消息字符串(即使这个字符串是存储在一个本地资源文件中)。这条代码语句需要传递name属性的值,这个值可以通过validationContext参数的DisplayName属性获得。构造完验证逻辑后,就可以将其应用到任何模型属性上:1[Required]2[StringLength(160)]3[MaxWords(10)]4publicstringLastName{get;set;}甚至可以赋予特性自定义的错误提示消息:1[Required]2[StringLength(160)]3[MaxWords(10,ErrorMessage="Therearetoomanywordsin{0}")]4publicstringLastName{get;set;}IValidatableObject自验证(self-validating)模型是指一个知道如何验证自身的模型对象。一个模型对象可以通过实现IValidatableObject接口来实现对自身的验证。下面在Order模型中直接实现对LastName字段中单次个数的检查:1publicclassOrder:IValidatableObject2{3publicIEnumerableValidate(ValidationContextValidationContext)4{5if(LastName!=null&&LastName.Split('').Length>10)6{7yieldreturnnewValidationResult("Thelastnamehastoomanywords!",new[]{"LastName"});8}9//....10}11}这种方式与特性版本有几个明显的不同点:MVC运行时为执行验证而调用的方法名称是Validate而不是IsValid,但更重要的是,它们返回类型和参数不同Validate的返回类型是IEnumerable,而不是单独的ValidationResult对象。因为从表面上看,内部的验证逻辑验证的是整个模型,因此可能返回多个验证错误。这里没有value参数传递给Validate方法,因为在此Validate是一个模型实例方法,在其内部可以直接访问当前模型对象的属性值。4.显示和编辑注解4.1DisplayDisplay特性可为模型属性设置友好的“显示名称”1[Required]2[StringLength(160)]3[Display(Name="LastName",Order=15001)]4publicstringFirstName{get;set;}4.2ScaffoldColumnScaffoldColumn特性可以隐藏HTML辅助方法(如EditorForModel和DisplayForModel)渲染的一些属性:1[ScaffoldColumn(false)]2publicstringUsername{get;set;}添加了这个特性之后,EditorForModel辅助方法将不再为Username字段显示输入元素和Label标签。然而需要注意的是,如果模型绑定器在请求中看到匹配的值,那么他仍然会试图为Username属性赋值。4.3DisplayFormat通过命名参数,DisplayFormat特性可用来处理属性的各种格式化选项。当属性包含空值时,可以提供可选的显示文本,也可以为包含标记的属性关闭HTML编码,还可以为运行时指定一个应用于属性值的格式化字符串。下面的代码可将模型的Total属性值格式化为货币值形式:1[DisplayFormat(ApplyFormatInEditMode=true,DataFormatString"{0:c}")]2publicdecimalTotal{get;set;}4.4ReadOnly如果需要确保默认的模型绑定器不使用请求中的新值来更新属性,可在属性上添加ReadOnly特性:1[ReadOnly(true)]2publicdecimalTotal{get;set;}4.5DataTypeDataType特性可为运行时提供关于属性的特定用途信息。例如,String类型的属性可应用与e-mail地址、URL或是密码。DataType特性可满足所有这些需求:1[Required]2[DataType(DataType.Password)]3[Display(name="Password")]4publicstringPassword{get;set;}其他的数据类型还有Currency、Date、Time和MultilineText。5其他特性UIHint:给ASP.NETMVC运行时提供了一个模版名称,以备调用模版辅助方法(如DisplayFor和EditorFor)渲染输出时使用。也可以定义自己的模版辅助方法来重写ASP.NETMVC的默认行为。找不到UIHint指定的模版时,MVC会寻找一个合适的替代模版使用。HiddenInput:渲染一个type特性值为“hidden”的输入元素。
-
ASP.NET MVC5入门指南1
1.创建项目文件-->新建-->项目VisualC#-->Web-->ASP.NETWeb应用程序MVC此时处于选中状态,勾选“添加单元测试”(可选择)。完成以上步骤,基本的项目创建完成,此时点击“F5”可运行项目,如下图所示。(为方便标识,此后用url代替“localhost:20391”)MVC代表:模型-视图-控制器。Models:标识该应用程序的数据并使用验证逻辑来强制实施业务规则的数据类Views:应用程序动态生成HTML所使用的模版文件Controllers:处理浏览器的请求,取得数据模型,然后指定要响应浏览器请求的视图模版2.添加一个控制器类(右击)Controllers文件夹-->添加-->控制器选择“MVC5控制器-空”为控制器添加名称添加后在Controllers文件夹中会多出文件“MvcMusicStoreController.cs”,并且在文件夹Views下会多出“MvcMusicStore”文件夹目录结构如下所示:修改控制器“MvcMusicStoreController.cs”文件中的代码为:1publicclassMvcMusicStoreController:Controller2{3publicstringIndex()4{5return"Thisismydefaultaction";6}78publicstringWelcome()9{10return"ThisisWelcomeactionmethod...";11}12}此时重新运行程序,地址栏输入“url/MvcMusicStore”3.数据路由ASP.NETMVC会调用不同的控制器类(和其内部不同的操作方法)这取决于传入URL。所使用的ASP.NETMVC的默认URL路由逻辑使用这样的格式来判定哪些代码以便调用:可在App_Start/RouteConfig.cs文件内通过配置URL路由解析规则:1publicclassRouteConfig2{3publicstaticvoidRegisterRoutes(RouteCollectionroutes)4{5routes.IgnoreRoute("{resource}.axd/{*pathInfo}");67routes.MapRoute(8name:"Default",9url:"{controller}/{action}/{id}",10defaults:new{controller="Home",action="Index",id=UrlParameter.Optional}11);12}13}如果运行程序且不提供任何URL段,默认为“Home”的控制器和Index的操作方法,在上面的代码中的defaults部分指定:第一部分的URL确定哪个控制器类会被执行。因此/MvcMusicStore映射到MvcMusicStoreController控制器类第二部分的URL确定要执行控制器类中的那个操作方法。因此/HelloWorld/Index,会使得MvcMusicStoreController控制器类的Index方法被执行。请注意,只需要浏览/MvcMusicStore路径,默认情况下会调用Index方法。如果没有明确的指定操作方法,Index方法会默认的被控制器类调用。第三部分的URL段(Parameters参数)是路由数据浏览url/MvcMusicStore/Welcome。Welcome方法会被运行并返回字符串“thisisthewelcomeactionmethod...”。默认的MVC映射为/[Controller]/[ActionName]/[Parameter]对于这个URL,控制器类是MvcMusicStore,操作方法是Welcome,此处并未用到[Parameters]部分。此处对Welcome方法进行修改,并使用了C#语言的可选参数功能,numTimes参数在不传值时,默认值为1。1publicstringWelcome(stringname,intnumTimes=1)2{3//return"ThisisWelcomeactionmethod...";4returnHttpUtility.HtmlEncode("Hello"+name+",NumTimesis:"+numTimes);5}此时运行应用程序并浏览次URL(url/MvcMusicStore/Welcome?name=Long&numtimes=4)上面的例子,没有用到URL段参数的部分(Parameters)。通过querystrings传递name和numTimes的参数用下面的代码替换“Welcome”的方法:1publicstringWelcome(stringname,intID=1)2{3//return"ThisisWelcomeactionmethod...";4//returnHttpUtility.HtmlEncode("Hello"+name+",NumTimesis:"+numTimes);5returnHttpUtility.HtmlEncode("Hello"+name+",ID:"+ID);6}这次URL第三部分的参数匹配了参数ID。4.添加一个视图控制器的默认程序是:1publicActionResultIndex()2{3returnView();4}上面的Index方法使用一个视图模版来生成一个HTML返回给浏览器。控制器的方法(也被称为actionmethod(操作方法)),如上面的Index方法,一般返回一个ActionResult(或从ActionResult所继承的类型),而不是原始的类型,如字符串。如果想使用控制器中默认的Index方法,则需要在对应的Views中添加视图文件。在Views/MvcMusicStore-->添加-->“MVC5ViewPagewith(LayoutRazor)”在指定项名称中,输入“Index”“选择布局页(selectlayoutpage)”-->"_Layout.cshtml"-->"确定",然后在解决方案资源管理器中看到View/MvcMusicStore/Index.cshtml文件。