首先,要纪念一下,这是我在博客园发表的第一篇文章 @*...*@ (好吧,我用了 Razor的注释符号)
前言
本人接触Web开发比较早,从最早使用C语言编写CGI开始,到Perl写的CGI,然后是ASP,PHP,一直在学习着基于Web的动态页面开发技术。前段时间转了一段时间的WPF,可后来又要做B/S的项目,同项目组成员进行讨论,选择了Asp.Net MVC3。08年就开始接触 Asp.net MVC 1.0,伴随着Asp.MVC的成长,也在很多项目里使用过Asp.MVC,见证了MVC的成长,也感觉这套框架的确还是很不错,尤其是3.0版本引入的Razor引擎。
关于Asp.MVC 3的一些基础知识,园子里已经有很多文章,这里不再赘述,主要分享一下在下的一些经验。
1、含HTML标记的内容输入与显示
输入:默认情况下与Asp Webform一样,是不允许提交含有Html标记的内容的,需要在接受输入的Action上标注 [ValidateInput(false)] 才能够提交数据。
[ValidateInput(false)] public SaveArticle(Article Model) { // do something }
输出:默认的,所有的使用@输出的内容都会被自动进行HTML编码,以更好的放置XSS 攻击。如果一定要输出HTML代码,例如富文本编辑器编辑的HTML代码。
<p>Hello world</p> ,输出的是 <p>Hello world</p>
如果需要强制输出为Html代码,则需要使用MVCHtmlString来输出,如下面的代码所示
@(new MvcHtmlString(article.Content))
这样就可以将Html代码原样输出到页面中
2、简单的 SEO Helper
在早期的Asp.net WebForm中,需要在 meta 中加入 keyword,description 是比较麻烦的事情。在 .net 4中得到了改观,能够直接使用代码设置这些属性,不过我们要在MVC中使用,还是得子自己来拼接这几个标签,得益于razor的语法,我们可以很简单的实现这个助手。
步骤:
0)首先在Layout(Master)页面中定义一个 SEO 的Section,代码如下
<head>
<title>@ViewBag.Title</title>
@RenderSection("SEO",false)
…….
1)在App_Code中添加一个 SEOHelper.cshtml文件(App_Code文件夹不存在就建一个)。有人可能要问为什么要放这里,主要是我没发现其他地方放进去之后,可以在项目所有位置能够正常引用的位置,如果有人发现了,还请告诉我。
2)删除SEOHelper.cshtml中的所有代码
3)输入下面的代码:
@helper Description(string description)
{
<meta name="DESCRIPTION" content="@description" />
}
@helper Keywords(string keywords)
{
<meta name="KEYWORDS" content="@keywords" />
}
@helper NoIndex()
{
<meta name="robots" content="noindex" />
}
4)在需要加入这些tag的页面
@section SEO
{
@SEOHelper.Description("This is the description for my site")
@SEOHelper.Keywords("keyword1,keyword2,keyword3")
}
浏览页面的时候,就能够自动加上这些<meta>标记了
Razor 的 helper支持非常方便,不用再写静态扩展方法,并自行拼接html代码。比如说分页控件,我就是使用helper直接封装成为一个助手方法。
3、使用强类型、添加了数据注解的Model类
使用强类型并添加注解的Model类有非常多的好处:
1)便于使用Html Helper生成表单,使用 LabelFor,TextBoxFor等等助手方法生成表单,文字信息根据注解的内容自动生成,控件的ID也是自动生成,不用担心与Model中的定义发生不匹配。
2)便于数据验证,使用 StringLength,Compare,Requried等标注,能够实现数据提交的自动验证;
3)数据自动绑定,表单提交过来的数据,都是字符串,还需要自行从Form集合中取出来,再进行数据类型转换,而使用Model,能够自动绑定到Model中的字段上
4)显示数据时强大的语法提示,这个大家都懂的
举个例子,新建的MVC工程选择Internet Application模板会自动创建的文件中,/Models/AccountModel.cs 中的ChangePasswordModel类,代码如下:
定义了两个必填字段,NewPassword字段必须少于100个字符,而ConfirmPassword必须与NewPassword字段相等。
public class ChangePasswordModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "当前的密码")]
public string OldPassword { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "新密码")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "确认新密码")]
[Compare("NewPassword", ErrorMessage = "新密码和确认密码不一致!")]
public string ConfirmPassword { get; set; }
}
生成表单的时候就只要这么写了:
@using (Html.BeginForm()) {
@Html.ValidationSummary(true, "Password change was unsuccessful. Please correct the errors and try again.")
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
@Html.LabelFor(m => m.OldPassword)
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.OldPassword)
@Html.ValidationMessageFor(m => m.OldPassword)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.NewPassword)
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.NewPassword)
@Html.ValidationMessageFor(m => m.NewPassword)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.ConfirmPassword)
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.ConfirmPassword)
@Html.ValidationMessageFor(m => m.ConfirmPassword)
</div>
<p>
<input type="submit" value="Change Password" />
</p>
</fieldset>
</div>
}
而在提交数据之后,直接使用Model获取数据
[Authorize]
[HttpPost]
public ActionResult ChangePassword(ChangePasswordModel model)
{
if (ModelState.IsValid)
{
// do something ...
}
// If we got this far, something failed, redisplay form
return View(model);
}
免去了众多繁琐的数据传递工作,让我们能够将更多的精力放在业务逻辑的处理上。
附加技巧:如果绑定时,希望某个字段不要使用绑定,可以使用如下标注
public ActionResult Create([Bind(Exclude = "OrderDate")] Models.CreateOrderModel model)
这样代码告诉Mvc不要将表单中的数据绑定到 OrderDate属性上;
4、如何处理View中的很多 object参数,例如说 object htmlAttributes, object routeValues
如果我们在生成表单的时候,需要再表单的元素上附加一些Html属性时,例如,我们要上传文件,需要给表单加上一个enctype属性:
看方法的语法提示:object htmlAttributes,这个object能够直接使用 new { @attributeName1 = attributeValue1, @attributeName2 = attributeValue2 }的方式定义并使用。
语法很像在Javascript中定义JSON对象对吧,不过冒号换成了等号。
另外为什么要在属性名称上加入 @ 符号的问题,不加@号其实也是可以的,我之前也不加@符号的,不过有一次遇到了一个需求,需要设置一个文本框为只读,遇到了 “readonly”这个Html属性,是个C#关键字,要是没 @ 符号,那就输不进来了,后来就习惯了都加上@符号。
---------------
给链接或其他加入参数
很多情况下,我们需要做一个带QueryString参数的链接,这个时候使用Html.ActionLink就可以按图上的代码所示实现,图上的代码,能够生成这样一个连接
http://localhost:2287/test/test3?userid=1&username=admin 不用我们手工拼接字符串
5、数据的传递
1)Controller -> View
- 可以通过 ViewBag这个Dynamic对象
- 通过Model【强烈建议使用】
- 通过ViewData这个上两代MVC遗留下来的Dictionary
2)View -> Action
- 强类型Model类,能够自动绑定到字段
- QueryString,Form表单,Json请求,也都能够将数据绑定到对应名称的单个参数之上,唯一要注意的就是名称一定要对应。
6、Html.RederPartial与Html.RenderAction
RenderPartial可用来显示一个部分视图,但是使用这个视图,如果有数据,必须通过RenderPartial("_partialView", dataObj)的方式传递过去。
我做过的项目中有这样一个需求,左边需要显示一个分类列表,这个分类列表不用说,就是从数据库中读出来的,最开始是使用RenderPartial,每次都要传数据过去,也就是说每次,我都要讲这个列表的数据放在当前页面的Model中作为一个子属性,然后再传给列表的部分视图页面,导致每个视图返回时,都要传这个列表数据过来。
后来改用Html.RenderAction,即可解决这个问题,这个Action也是返回一个部分视图,列表目录的数据由这个action提供,还可以把这个Action放在缓存中,让当前页面传递的数据变得简单。
使用原则:如果这个部分视图,不需要出页面上自带数据之外的数据,使用RenderPartial,如果需要额外的数据,使用Html.RenderAction来实现更为简洁
另外:Html.Partial 与 Html.RenderPartial的区别
@Html.Partial("_logonPartial")
@Html.RenderPartial("_TopPartial") 这么写是会报错的哦,要这么写 @{Html.RenderPartial("_TopPartial");}
各位看官应该看出区别出来了,我想大家都能看懂的....