1.利用方法HttpUtility.HtmlEncode来预处理用户输入。这样就能阻止用户用链接向视图中注入JavaScript代码或HTML标记,比如//Store/Browse?Genre=<script>window.location='http://hacker.example.com'</script>。
例如:
public string Browse(string genre) { string message = HttmpUtility.HtmlEncode("Store.Browse,Genre = "+genre); return message; }
2.return到非默认视图
1)同一Controller下
public ActionResult Index() { return View("NotIndex"); }
2)非同一Controller下
public ActionResult Index() { return View(~/Views/Example/Index.cshtml"); }
注意:为了在查找视图时避开视图引擎的内部查找机制,在使用这种语法时,必须提供视图的文件扩展名。
3.ViewBag是ViewData的动态封装器,ViewBage.CurrentTime 等同于 ViewData["CurrentTime"].
4.Razor存在二义性时,使用@()输出表达式。
5.Razor中转义@,使用@@。
6.Razor会简单区分Email。
7.Razor表达式是用HTML自动编码的,即不会受到脚本注入攻击。但以下情况特殊:
例如:
<script type ="text/javascript"> $(function(){ var message = 'Hello @ViewBag.Username'; $("message").html(message).show('slow'); }); </script>
在这段代码中,将一个字符串赋值给了javaScript变量message,而且该字符串中包含了用户通过Razor表达式提供的用户名。通过jQuery的HTML方法,变量message将被设置为一个ID属性值为"message"的Dom元素。
尽管在message字符串中对用户名进行了HTML编码,但是仍然具有潜在XSS脆弱性。例如,如果用户提供一下的字符串作为用户名,HTML将被设置为一个脚本标签:
x3cscriptx3e%20alert(x27pwndx27)%20x3c/scriptx3e 当在JavaScript中将用户提供的赋值给变量时,要使用JavaScript杜甫川编码而不仅仅是HTML编码,记住这一点是很重要的。
也就是要使用@Ajax.JavaScriptStringEncode方法对用户输入进行编码。下面是使用了这个方法的相同代码,这样就可以有效的避免XSS攻击:
<script type ="text/javascript"> $(function(){ var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Username)'; $("message").html(message).show('slow'); }); </script>
8.如果想呈现html:
@{ string message = "<strong>Thisi is bold!</strong>";}
使用<span>@Html.Raw(message)</span> 结果:<span><strong>Thisi is bold!</strong></span>
9.Razor语法
变量或有返回值的方法:@Data.Data
代码块:{string a = "data one"; ViewBage.Title = "Another data";}
foreach块(if块):
@foreach(var item in stuff)
{
<li>The item name is @item.</li>
}
没有返回值的方法:
@{Html.RenderPartial("SomePartial");}
10.Razor调用泛型方法使用() @(Html.SomeMethod<AType>())
11.布局页及页脚的使用:
SiteLayout.cshtml:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="main_content">@RenderBody() </div> <footer> @if (IsSectionDefined("Footer")) { @RenderSection("Footer"); } else { <span>This is the default footer.</span> } </footer> @*<footer>@RenderSection("Footer")</footer>*@ </body> </html>
TestLayout.cshtml
@{ ViewBag.Title = "TestLayout"; Layout = "~/Views/Shared/SiteLayout.cshtml"; } <h2>引用了TestLayout布局页</h2> @section Footer { This is the <strong>custem footer!</strong>. }
12.加载局部页面
局部页面controller:
public ActionResult Message() { ViewBag.Message = "This is a partial view."; return PartialView(); }
局部也面html:
<h2>@ViewBag.Message</h2>
调用页面Controller:
public ActionResult TestPartialView() { return View(); }
调用页面html (需要引用js):
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <script src="~/Scripts/jquery-1.10.2.js"></script> <title>TestPartialView</title> <script type="text/javascript"> $(function () { $('#result').load('/Store/Message'); }); </script> </head> <body> <div id="result"></div> </body> </html>
13.导航属性和外键属性
public partial class Album { public virtual int AlbumID { get; set; } public virtual int GenreID { get; set; } public virtual int ArtistID { get; set; }//外键属性 foreign key property public virtual string TitleContent { get; set; } public virtual Genre Genre { get; set; } public virtual Artist Artist { get; set; }//导航属性 navigational property }
备注:有了外键属性,数据库就会建立外键。有了导航属性,就可以在Album中导航到对应的Artist 信息。 *外键属性也可以不用。
14.EF规定
1)Album类生成表名为Albums
2)如果存储对象中有一个名为ID的属性,EF就假设这个属性值就是主键值,并把这个值赋给SQL Server中对应的自动递增(标识)列。
15.EF上下文添加及连接字符串添加
1)编写数据表所对应的MODEL
2)添加带有CRUD功能的控制器,使用EF
3)选择MODEL
4)选择上下文,点击右边的加号添加
5)确定,vs自动生成webconfig基架和dbcontext基架,并根据需求生成带有CRUD的controller基架。
16.dbcontext基架顶部注释内容:
1)现在代码归我们所有。Dbcontext的创建时一次性完成的,所以可以自由修改这个类,不用担心所做修改会被重写。
2)代码归我们负责。我们需要确保对模型类所做的修改能够会反映到数据库中,反之亦然,既对数据库的修改也会反映到模型类中。EF通过使用数据迁移来帮我们完成这项工作。
17.CRUD Controller基架解释
public class AlbumsController : Controller { private MvcMusicStoreContext db = new MvcMusicStoreContext(); // GET: Albums public ActionResult Index() { var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre); return View(albums.ToList()); } //more later...
在Index操作中Include方法的调用告知实体框架在加载一个专辑的相关流派和艺术家信息时采用预加载策略。预加载策略就是尽其所能的使用查询语句加载所有数据。
实体框架的另一种(默认的)策略是延迟加载策略。使用延迟加载策略,EF在LINQ查询中之家在主要对象(专辑)的数据,而不填充Genre和Artist属性:var albums = db.Albums;
延迟加载根据需要来加载相关数据,也就是说,只有当需要Album的Genre或Artist属性时,EF才会通过向数据库发送一个额外的查询来加载这些数据。然而不巧的是,当初李专辑信息时,延迟加载策略会强制框架为列表中的每一个专辑向数据库发送一个额外的的查询。对于含有100个专辑的列表,如果要加载所有的艺术家数据,延迟加载则总共需要101个查询。这里描述的清醒就是N+1问题(因为框架要执行101个查询才能得到100个填充了得对象),这是使用对象关系映射框架面临的一个共同问题。看来延迟加载在带来便利的同时也可能要付出潜在的代价。
这里可将Include方法看成减少在构建完整模型中需要的查询数量的一个优化。
18.为EF上下文配置数据链接,有两种方式。
1)在webconfig文件中添加链接字符串,链接字符串名称必须与数据上下文类的名称一致。如:
<connectionStrings> <add name="MusicStoreDB" connectionString="data source=.MyWonderfulServer; Integrated Security=SSPI; initial catalog=MusicStore" ProviderName="System.Data.SqlClient" </connectionStrings>
2)通过修改传递给DbContext的构造函数的name参数,可以重写EF将为给定DbContext使用的数据库名称:
public MusicStoreDB():base("name=SomeOtherDatabase"){}
这个name参数允许指定数据库名称(这里指定了SomeOtherDatabase儿不是MusicStoreDB)。也可以通过这个name参数传递一个完整的链接字符串,这样就可以全面控制每个DbContext的数据存储。
19.EF默认数据库
如果不配置具体的链接,EF将尝试链接SQL Server的LocalDB实例,并且查找与DbContext派生类同名的数据库。如果EF能够链接到数据库服务器,但找不到数据库,那么框架将会创建一个数据库。
20._MigrationHistory表用于追踪模型状态,EF并不严格要求数据库中有一个此表,删除此表后需要手动维护数据库。
21.使用数据库初始化器
Global.asax.cs
protected void Application_Start() { Database.SetInitializer( new DropCreateDatabaseIfModelChanges<MvcMusicStoreContext>() ); AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
DropCreateDatabaseIfModelChanges类和DropCreateDatabaseAlways类,选择使用。
22.播种数据库
1)重写以上使用类的Seed方法,在Model中添加类MusicStoreDbInitializer继承自以上使用类
public class MusicStoreDbInitializer:System.Data.Entity.DropCreateDatabaseIfModelChanges<MvcMusicStoreContext> { protected override void Seed(MvcMusicStoreContext context) { context.Artists.Add(new Artist { Name = "Al Di Meola" }); context.Genres.Add(new Genre { Name="Jazz"}); context.Albums.Add(new Album { Artist = new Artist { Name = "Rush" }, Genre = new Genre { Name = "Rock" }, Title = "Caravan", Price = 9.99m }); base.Seed(context); } }
2)注册初始化器 Global.asax.cs
protected void Application_Start() { Database.SetInitializer( new DropCreateDatabaseIfModelChanges<MvcMusicStoreContext>() ); Database.SetInitializer(new MusicStoreDbInitializer() ); AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
23.数据库链接字符串,虽然已经生成,但需要做数据库的对应修改
<add name="MvcMusicStoreContext" connectionString="server=.;database=MusicStoreDB;integrated security=false;user id=sa;password=sasa" providerName="System.Data.SqlClient"/>
24.使用基架生成页面时,如果引用了布局页_ViewStart.cshtml,则会出现以下错误:
类型“ASP._Page__ViewStart_cshtml”不从“System.Web.WebPages.StartPage”继承。
取消对_ViewStart.cshtml的引用即可。
25.以上步骤总结:
1)实现模型类
2)微控制器和视图构建基架
3)选择数据库初始化策略
26.Edit中根据模型创建下拉列表
ViewBag.ArtistID = new SelectList(db.Artists, "ArtistID", "Name", album.ArtistID); ViewBag.GenreID = new SelectList(db.Genres, "GenreID", "Name", album.GenreID);
代码中使用的SelectList类用于表示构建下拉列表需要的数据。其中构造函数的第一个参数制定了将要放在列表中的项(这里db是数据库上下文,即去了整张表的列表)。第二个参数是值(dropdownlist value)。第三个参数是名称(dropdownlist Text)。第四个参数是最初的选定项(select value)。
<div class="col-md-10"> @Html.DropDownList("GenreID", null, htmlAttributes: new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.GenreID, "", new { @class = "text-danger" }) </div>
前台中,使用Html DropDownlist辅助方法,第一个参数是名称(html控件ID和name),第二个是枚举序列。MVC通过控件名称与模型属性对应,即input和select元素的name属性要和Album模型中的属性名称匹配,这就是其名称剪短的原因所在。这就是ASP.NET MVC提供的模型绑定功能。
HTML辅助方法:
27.Form (资源路径可变表单)
@using(Html.BeginForm("Action","Controller",FormMethod.Get,new {target = "_blank"})) { <input type="text" name="q" /> <input type="submit" value="Search" /> }
以上代码中,向BeginForm方法的htmlAttributes参数传递了一个匿名类型的对象。在ASP.NET MVC框架的重载版本中,几乎每一个HTML辅助方法都包含HTMLAttributes参数。
如果using语句无法正确生成,可如下使用:
@{Html.BeginForm("Search","Home",FormMethod.Get);} <input type="text" name="q" /> <input type="submit" value="Search" /> @{Html.EndForm();}
28. TextArea (Html辅助方法生成的html标记可以避免跨站点脚本攻击)
@Html.TextArea("text","hello <br/> world")
29.关键字使用@转义
@using(Html.BeginForm("Action","Controller",FormMethod.Get,new {target = "_blank",@class="editForm"}))
30.html中连接符在C#中使用下划线表示,在form表单中加入客户端验证
@using(Html.BeginForm("Action","Controller",FormMethod.Get,new {target = "_blank",@class="editForm",data_validatable=true}))
31.不带参数的BeginForm和排除属性级别的错误
@using(Html.BeginForm()){ @Html.ValidationSummary(excludePropertyErrors:ture) <fieldset> <legend>Edit Album</legend> <p> <input type="submit" value="Save"> <p> </fieldset> }
手动测试报错方法
ModelState.AddModelError("","This is all wrong!"); ModelState.AddModelError("Title","What a terrible name!");
第一个是模型级别的错误,因为代码中没有提供错误与特定属性关联的键,第二个是与Title属性相关的错误,因此视图中的验证摘要区域不会显示这个错误。
32.输入元素
1)Html.TextBox and Html.TextArea
@Html.TextBox("Title",Model.Title) @Html.TextArea("text","Hello <br/> world") @Html.TextArea("text","Hello <br/> world",10,80,null) 上面的TextArea生成html如下: <textarea cols="80" id="text" name="text" rows="10">Hello <br /> world </textarae>
2)Html.Label
Html.Lable("GenreId") 生成 <label for="GenreId">Genre</label>
在可能的情况下,辅助方法使用任何可用的模型元素数据来生成显示内容。
3)Html.DropDownList and Html.ListBox
DropDownList和ListBox辅助方法都烦一个<select/>元素,前者单选,后者多选。
Album album = db.Albums.Find(id); if (album == null) { return HttpNotFound(); } ViewBag.ArtistID = new SelectList(db.Artists, "ArtistID", "Name", album.ArtistID); ViewBag.GenreID = new SelectList(db.Genres, "GenreID", "Name", album.GenreID); return View(album);
基架使用反射提取list元素会有一定资源开销,如想避免可使用LINQ的Select方法
4)Html.ValidationMessage
当ModelState字典中的某一特定字段出现错误时,可以使用ValidationMessage辅助方法来显示相应的错误提示消息。
@Html.ValidationMessage("Title") ModelState.AddModelError("Title","What a terrible name!");
5)辅助方法、模型和视图数据
6)强类型辅助方法
7)辅助方法和模型元数据
8)模板辅助方法
9)辅助方法和ModelState
用来显示表单值得所有辅助方法也需要与ModelState交互。ModelState是模型绑定的副产品。并且存储模型绑定期间的所有验证错误,以及用户提交用来更新模型的原始值。
tmd 总是丢数据 不写了