mvc 特点:
逻辑分离
容易测试
开发的主流
cshtml文件中c#代码的写法(Razor):
1. @{var total=7; }
2. <p> total value is : @total </p>
<!-- html注释 -->
3. @{
@* 注释 *@
/*注释 */
ViewBag.title = "Index";
Layout="~/Views/Shared/_Layout.cshtml";
}
@RenderBody() 调用子视图
浏览器中 ,按 f5 刷新, ctrl+f5 清空缓存刷新
visual studio中, f5调试运行,ctrl+f5 不调试运行。
Best Practice
ViewBag用于在controller和view之间传递参数,例如:
url 传递参数给action, 如: /hello/welcome?name=jim&numTimes=9
属性加attribute
[Display(Name ="发布日期")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString ="{0:yyyy-MM-dd}",ApplyFormatInEditMode =true)]
public DateTime ReleaseDate { get; set; }
用法
@model IEnumerable<MVC1.Models.Movie>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
效果如下:
防止跨页请求攻击
在action前面加attribute [ValidateAntiForgeryToken]
在cshtml中 , 加 @Html.AntiForgeryToken()
此代码会最终渲染成html中的如下代码:
<input name="__RequestVerificationToken" type="hidden" value="elnxG8LVY_AMtLIbt87sJ49vxdmXorN-HJE3O3QYIMKLluVogLcVJuh4yn3UMF8l3TT1sbnpXNeahhALld-v6HE69kflG6ZrfqCpzTg5k5k1" />
如上图,Bind用于model绑定,在此处限制仅允许编辑Moive中的某些属性。
[ActionName("Delete")]
更改action暴露到url中的名称
<p>
@Html.ActionLink("Create New", "Create")
@using (Html.BeginForm("Index","Movies",FormMethod.Get))
{
<p>
Title:@Html.TextBox("searchString","a") |
Genre: @Html.DropDownList("movieGenre","all")
<input type="submit" value="Filter"
/>
</p>
}
</p>
@Html.TextBox("searchString","a") , a 为默认值,searchString为名字,也是提交表单时的字段名
同样,@Html.DropDownList("movieGenre","all") "all" 为默认值,movieGenre为控件名字,也是提交表单时的字段名,同时也设置了下拉列表数据源为ViewBag.movieGenre
对应的后台代码为
public ActionResult Index(string searchString, string movieGenre)
{
var genreList = new List<string>();
var movieGenres = from movie in db.Movies select movie.Genre;
genreList.AddRange(movieGenres.Distinct());
ViewBag.movieGenre = new SelectList(genreList);
var movies = from movie in db.Movies select movie;
if (!string.IsNullOrEmpty(searchString))
{
movies = movies.Where(m => m.Title.Contains(searchString));
}
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(m => m.Genre == movieGenre);
}
return View(movies);
}
属性校验
[StringLength(60,MinimumLength=3)] //最多为60,最少为3
public string Title {get;set;}
Title编辑时效果为:
[RegularExpression(@"^[A-Z]+[a-zA-Z''-'s]*$")] //正则表达式
[Required] //必须
[StringLength(30)]
public string Genre {get;set;}
[Range(1,100)] //范围
[DataType(DataType.Currency)]
public decimal Price{get;set;}
Price 显示效果为
浏览器禁用了js脚本(活动脚本)后,点击提交,后台 ModelState.IsValid 为 false,最终效果如下:
验证信息 对应cshtml文件里的如下代码:
@Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
路由设置
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "news",
url: "{year}-{month}-{id}",
defaults: new { controller = "News", action = "Index"},
constraints: new { year = "^\d{4}$",month="^\d{1,2}$"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}", //去掉 id = UrlParameter.Optional ,可以写成"{controller}/{action}/{?id}"
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Constraints:为参数添加约束(使用正则表达式)
{controller}、{action} 为固定写法,匹配控制器名称和action名称
其它,如{year} 匹配参数,如下获取、使用参数
在view中显示
最终效果如下:
总结:
路由测试
1)引用程序集 RouteDebug.dll
2)在Global.asax中添加 RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
3) 打开页面,测试,效果如下:
例二:
路由操作中用到的4个类型
Route, RouteData, RouteCollection, RouteTable