ASP.NET是使用HTML蚁飒、CSS琼懊、JS和服務(wù)端腳本創(chuàng)建Web頁面和網(wǎng)站的開發(fā)框架哼丈。
ASP.NET支持三種開發(fā)模式
- Web Pages:Web頁面
- MVC:Model View Controller 模型-視圖-控制器
- Web Forms:Web窗體
基于.NET平臺開發(fā)站點的框架實際上包含兩部分:可視化用戶界面WebForm和后臺Web組件ASP.NET削祈。兩者通過命名空間區(qū)分咙崎,System.Web.UI.*
命名空間下的內(nèi)容可稱為WebForm褪猛,而System.Web.*
命名空間下的內(nèi)容可稱為ASP.NET伊滋。
與WebForm一樣笑旺,ASP.NET MVC的類都在System.Web.Mvc
命名空間下,也是基于ASP.NET平臺構(gòu)建的乌妙。
MVC 編程模型
MVC 是使用模型-視圖-控制器設(shè)計創(chuàng)建Web程序的模式
- Model 模型,表示應(yīng)用程序核心泽艘,如數(shù)據(jù)庫記錄列表悉盆。
模型是應(yīng)用程序中用于處理應(yīng)用程序數(shù)據(jù)邏輯的部分秋秤,模型對象負(fù)責(zé)在數(shù)據(jù)庫中存取數(shù)據(jù)灼卢。
模型是定義應(yīng)用程序主題的現(xiàn)實對象鞋真、過程以及規(guī)則的表示海诲,稱為域(Domain)特幔。
模型通常被稱為域模型(Domain Model)薄风,包含應(yīng)用程序域中要建立的C#對象遭赂,稱為域?qū)ο螅―omain Object)嵌牺。這些域?qū)ο髽?gòu)成了應(yīng)用程序的全部事物以及操作這些對象的方法。視圖和控制器以一致的方式將域暴露給客戶端僻弹。一個設(shè)計良好的MVC應(yīng)用程序蹋绽,必須從設(shè)計良好的模型開始,隨后添加控制器和視圖的焦點蚣抗。 - View 視圖翰铡,顯示數(shù)據(jù)
視圖是應(yīng)用程序中處理數(shù)據(jù)顯示的部分,視圖是依賴模型數(shù)據(jù)創(chuàng)建的迷捧。 - Controller 控制器漠秋,處理輸入
控制器是應(yīng)用程序中處理用戶交互的部分手趣,控制器負(fù)責(zé)從視圖讀取數(shù)據(jù)绿渣,控制用戶輸入,并向模型發(fā)送數(shù)據(jù)淀散。
MVC分層有助于管理復(fù)雜的應(yīng)用程序,同時也簡化分組開發(fā)郭膛。
MVC框架被構(gòu)建成一系列獨立的組件,這些組件滿足一個.NET接口棍现,或建立在一個出抽象類之上。你可以很容易地用一個自己的不同實現(xiàn)來替換這些組件朴肺。例如:路由系統(tǒng)西土、視圖引擎、控制器工廠等般甲。通常,MVC框架對每個組件提供三種選擇:
- 使用組件現(xiàn)行的默認(rèn)實現(xiàn)
- 派生默認(rèn)實現(xiàn)的一個子類以調(diào)整其行為
- 用接口或抽象基類的一個新的實現(xiàn)來完全替換該組件
ASP.NET MVC 開發(fā)中有一個很重要的理念叫“約定大于配置”,ASP.NET MVC中存在許多潛規(guī)則:
- 控制器存放
controller
目錄涮俄,命名以Controller
結(jié)尾彻亲。 - 每個控制器都對應(yīng)
View
中一個目錄,視圖目錄名稱跟控制器同名野来。控制器中的方法名都對應(yīng)一個View
視圖舀患,且視圖名字跟Action
動作的名字相同。 - 控制器必須是非靜態(tài)類低匙,且要實現(xiàn)
IController
接口。 - 控制器類型可以放到其他項目中
ASP.NET MVC的請求處理流程
客戶端請求 => IIS => Runtime => Controller => Action => ViewResult(:ActionResult) => ExecuteResult() => RazorView(:IView).RenderView => Response
ASP.NET MVC 目錄結(jié)構(gòu)
- 應(yīng)用程序信息
Properties
References
- 應(yīng)用程序目錄
App_Data
Content
存放靜態(tài)文件绞呈,如CSS佃声、ICON、IMG召嘶。
Controllers
負(fù)責(zé)處理用戶輸入和響應(yīng)的控制器類,命名以Controller
結(jié)尾铛只。
Models
包含表示應(yīng)用程序模型的類,控制并操作應(yīng)用程序的數(shù)據(jù)蜕着。
Views
用于存儲與應(yīng)用的顯示相關(guān)的HTML界面文件。該目錄包含每個控制器對應(yīng)的一個目錄韧骗。
Scripts
存儲應(yīng)用程序的JS文件 - 配置文件
Global.asax
packages.config
Web.config
ASP.NET MVC
路由
任何時候一個請求進來,URL都會與已注冊的路由模板進行匹配政模。如果找到匹配項,就會確定處理該請求的合適控制器和操作方法习蓬。如果沒有找到,請求會被拒絕枫慷,結(jié)果通常是一個404消息。
應(yīng)用程序路由通常是在global.asax
文件中注冊,并在應(yīng)用程序啟動時得到處理足丢。
$ vim global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
}
URL路由引擎是一個把PostResolveRequestCache
事件串聯(lián)起來的HTTP模塊,在檢查出請求的響應(yīng)不在ASP.NET緩存中以后,就會出發(fā)該事件袖订。
$ vim App_Start/RouteConfig.cs
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Movie
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
框架所支持的路由必須添加到由ASP.NET MVC管理的路由對象的靜態(tài)集合中,該集合就是RouteTable.Routes
吏口。通常使用便捷的MapRoute()
方法來填充該集合。如果需要在路由上做一些MapRoute()
并不支持的設(shè)置,需要使用
var route = new Route(...);
RouteTable.Routes.Add("RouteName", route);
路由約束
routes.MapRoute(
"Product",
"{controller}/{id}/{locale}",
new {controller = "Product", action="Index", locale="en-us"},
// 路由約束
new {id = @"\d{8}", locale="[a-z]{2}-[a-z]{2}"}
)
從技術(shù)角度看塘娶,路由處理程序是一個實現(xiàn)IRouteHandler
接口的類
public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}
在System.Web.Routing
命名空間中定義的 RequestContext
類痊夭,封裝了請求的HTTP上下文及任何可用的路由專用信息刁岸,比如Route對象本身、URL參數(shù)和約束條件她我。這些數(shù)據(jù)被分組到一個RouteData
對象虹曙。
public class RequestContext
{
public RequestContext(HttpContextBase httpContext, RouteData routeData);
// properties
public HttpContextBase HttpContext {get; set;}
public RouteData RouteData {get; set;}
}
阻止已定義的URL路由
- 為需要阻止的URL定義一個模式并保存到一個路由
- 將該路由鏈接到一個專門的路由處理程序
StopRoutingHandler
類
其結(jié)果就是在調(diào)用GetHttpHandler()
時會拋出一個NotSupported
異常番舆。
$ vim /App_Start/RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
// 強制路由系統(tǒng)處理所有的請求
// routes.RouteExistingFiles = true;
// 指示路由系統(tǒng)忽略任何.axd請求
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces:new[] { "App.Controllers"}
);
}
IgnoreRoute
所作的就是將StopRoutingHandler
路由處理程序關(guān)聯(lián)到圍繞指定URL模式所構(gòu)建的路由上酝碳。
控制器
控制器主要負(fù)責(zé)響應(yīng)用戶的輸入,關(guān)注的是應(yīng)用程序流恨狈、輸入數(shù)據(jù)的處理以及對相關(guān)視圖輸出數(shù)據(jù)的提供疏哗。
控制器的特征
- 繼承自
System.Web.Mvc.Controller
,實現(xiàn)IController
接口禾怠。 - 一個
Controller
可包含多個Action
返奉,每個Action
都是一個方法,返回一個ActionResult
實例刃宵。
控制器本身是一個類衡瓶,該類只要是public
公開的方法就會被是為是一個動作方法Action
,只要動作存在就可以接收客戶端傳來的請求牲证,經(jīng)過處理后返回響應(yīng)的視圖View
哮针。
public string Text()
{
return "hello world";
}
在定義一個方法時會根據(jù)方法有無返回值來劃分,但是控制器的本質(zhì)是類坦袍,控制器的動作action
本質(zhì)是方法十厢。從數(shù)學(xué)集合的角度來看,控制器是類的子集捂齐,控制器的動作是方法的子集蛮放。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Movie.Controllers
{
public class TestController : Controller
{
// http://localhost:49184/test
public string Index()
{
return "hello";
}
// http://localhost:49184/test/welcome?name=superman&age=30
public string Welcome(string name, int age = 0)
{
// HttpServerUtility.HtmlEncode 來保護應(yīng)用從malacious輸入的(也就是JavaScript)
return HttpUtility.HtmlEncode("welcome "+name+" age is "+age);
}
}
}
控制器的基本條件
- 控制器必須為
public
公開類別 - 控制器名稱以
Controller
結(jié)尾 - 控制器必須繼承ASP.NET MVC內(nèi)置
Controller
類或?qū)崿F(xiàn)IController
接口 - 控制器內(nèi)的所有動作必須為
public
公開方法,任何非public
方法均不會被視為動作方法奠宜。
控制器的運行原理
當(dāng)控制器被MvcHandler
選中后包颁,通過ActionInvoker
選定適當(dāng)?shù)?code>Action來運行。在Controller
中每個Action
可定義0到n個參數(shù)压真,ActionInvoker
會根據(jù)當(dāng)前的RouteValue
與客戶端傳遞來的數(shù)據(jù)娩嚼,準(zhǔn)備可傳入Action
參數(shù)的數(shù)據(jù),最后調(diào)用Controller
中被選中的Action
方法滴肿。
HTTP動詞
ASP.NET MVC可讓你將方法綁定到用于特定HTTP動詞的操作岳悟,要將控制器方法與HTTP動詞關(guān)聯(lián),可使用參數(shù)化的AcceptVerbs
特性,也可以直接使用特性贵少。使用AcceptVerbs
特性呵俏,可以指定需要哪個HTTP動詞來執(zhí)行給定的方法。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update(Customer customer)
{
...
}
AcceptVerbs
特性會從HttpVerbs
枚舉類型中提取滔灶,HttpVerbs
枚舉由Flags
特性修飾普碎。
public enum HttpVerbs
{
Get = 1,
Post = 2,
Put = 4,
Delete = 8,
Head = 0x10
}
可通過按位OR
(|)運算符將來自枚舉類型的枚舉值結(jié)合到一起,同時獲得另一個HttpVerbs
值宽气。
[AcceptVerbs(HttpVerbs.Post|HttpVerbs.Put)]
public ActionResult Edit(Customer customer)
{
...
}
控制器的方法類別
- 動作方法選定器
當(dāng)通過ActionInvoker
選定Controller
控制器中的public
公開方法時随常,ASP.NET MVC的“動作方法選定器(Action Method Selector)”便會運行在動作方法上潜沦,以便ActionInvoker
選擇對應(yīng)的Action
萄涯。
- NonAction 屬性
若控制器的動作方法上的特性為NonAction
,則表示該Action
是“公開方法”唆鸡,即告知ActionInvoker
不要選擇此Action
來運行涝影。
NonAction
屬性的作用:
保護Controller
中特定的公開方法不要發(fā)布到Web上
功能尚未開發(fā)完畢就要進行部署,但暫時不想將此方法刪除争占。
可將public
修改為private
達到同樣的保護效果
private ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
- HTTP動詞限定屬性
HTTP動詞限定屬性包括HttpGet
燃逻、HttpPost
、HttpDelete
臂痕、HttpPut
伯襟、HttpHead
、HttpOptions
握童、HttpPatch
姆怪,它們都是動作方法選定器的一部分。
// 當(dāng)客戶端瀏覽器發(fā)送的是HTTP GET請求時各聘,ActionInvoker才會選定此Action鳍侣。
[HttpGet]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
[HttpPost]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
- 操作過濾器
一個操作方法 一旦被選中就會立即執(zhí)行党巾,且返回一個結(jié)果,返回的結(jié)果也會隨之執(zhí)行溪掀。
ASP.NET MVC 提供5種操作過濾器:身份驗證、授權(quán)步鉴、操作前后處理揪胃、結(jié)果前后處理、處理處理氛琢。此外還有一種是重寫過濾器喊递,它允許為全局或控制器的默認(rèn)集合制定例外規(guī)則。
操作過濾器可直接使用操作方法或控制器的特性來編寫艺沼,也可以作為在全局過濾器列表中注冊的單獨類來編寫册舞。如果打算將編寫的操作過濾器作為特性來使用,就必須繼承FilterAttribute
類或其子類障般,例如ActionFilterAtrribute
调鲸。當(dāng)然不作為特性使用的全局操作過濾器對這個基類是沒有要求的盛杰。注意的是,無論采用哪個路由藐石,操作過濾器支持的過濾活動都由實現(xiàn)的接口所決定即供。
MvcHandler
從Controller
得到ActionResult
之后,開始運行ActionResult
提供的ExecuteResult
方法于微,并將運行結(jié)果響應(yīng)到客戶端逗嫡,此時Controller
的任務(wù)完成。
控制器的動作過濾機制
- 授權(quán)過濾器
AuthorizationFilters
- 動作過濾器
ActionFilters
- 結(jié)果過濾器
ResultFilters
- 例外過濾器
ExceptionFilters
動作
Action本質(zhì)是類中的公共方法可重載株依,要求參數(shù)不同驱证。Action可通過路由規(guī)則傳遞數(shù)據(jù)。Action方法接收瀏覽器傳遞的參數(shù)恋腕。若希望方法只處理某種請求抹锄,可在方法前添加特性[HttpGet]
或[HttpPost]
,處理請求時會根據(jù)參數(shù)調(diào)用對應(yīng)方法荠藤。
獲取Request對象中的輸入數(shù)據(jù)
ASP.NET中Request.Params
字典產(chǎn)生于4個不同字典的組合伙单,即QueryString
、Form
哈肖、Cookies
吻育、ServerVariables
∮倬可使用Request
對象的Item
索引器屬性布疼。
POST數(shù)據(jù)接收方法包括:Request.Form
、Form.Collection
庄吼、同名參數(shù)缎除、Model
。GET數(shù)據(jù)接收方式可直接通過Request.QueryString
獲取总寻。
public ActionResult Echo()
{
var data = Request["param"] ?? String.Empty;
}
public ActionResult Echo()
{
var data = Request.Params["param"] ?? String.Empty;
}
從路由中獲取輸入數(shù)據(jù)庫
ASP.NET MVC會通過URL提供輸入的參數(shù)器罐,參數(shù)值由路由模塊捕獲以供應(yīng)用程序使用。路由值不通過Request
對象向應(yīng)用程序空開渐行。
public ActionResult Echo()
{
var data = RouteData.Values["param"] ?? String.Empty;
}
路由數(shù)據(jù)是通過Controller
類的RouteData
屬性公開的轰坊,對匹配項的搜索不區(qū)分大小寫。RouteData.Values
字典是一個字符串/對象字典祟印,大多數(shù)時候該字典只包含字符串肴沫。但是,若以編程方式填充該字典蕴忆,那么它就可以包含其他類型的值颤芬。
public ActionResult Echo()
{
var data = RouteData.Values["data"] ?? (Request.Params["data"] ?? String.Empty);
}
ValueProvider字典
在Controller
類中ValueProvider
屬性只會為從各種來源收集到的輸入數(shù)據(jù)提供單個容器。默認(rèn)情況下,ValueProvider
字典來自下列源的輸入值填充:
- 子操作值
- 表單數(shù)據(jù)
Request.Form
- 路由數(shù)據(jù)
- 查詢字符串
- 提交的文件
ValueProvider
字典提供了一個以GetValues()
方法為中心的自定義編程接口站蝠。
var result = ValueProvider.GetValue("param");
GetValue()
不會返回String
或Object
類型汰具,而會返回ValueProviderResult
類型的一個實例。該類型有兩個用于實際讀取真實參數(shù)值的屬性:RawValue
和AttemptedValue
菱魔,前者是Object
類型留荔,包含來源所提供的原始值。AttemptedValue
屬性卻是一個字符串澜倦,代表了強制轉(zhuǎn)換為String
類型的結(jié)果聚蝶。
public ActionResult Echo()
{
var data = ValueProvider.GetValue("param").AttemptedValue ?? (ValueProvider.GetValue("param").AttemptedValue ?? String.Empty);
}
ValueProvider
比Request
和RouteData
在參數(shù)名稱上的要求更高一些,如果參數(shù)大小寫輸入錯誤藻治,會得到一個從GetValue
返回的null
對象碘勉。如果之后只是讀取值而不檢查為空的結(jié)果對象,就會導(dǎo)致一個異常栋艳。最后要注意的是恰聘,默認(rèn)情況下句各,不能通過ValueProvider
字典獲得對Cookies
的訪問權(quán)吸占。可通過定義一個實現(xiàn)IValueProvider
接口的類凿宾,值提供器列表可以以編程方式得到擴展矾屯。
參數(shù)傳入的屬性均通過模型綁定機制(Model Binding),從RequestContext
請求上下文中獲取數(shù)據(jù)初厚,并將數(shù)據(jù)傳入對應(yīng)的方法參數(shù)中件蚕,讓Action
動作方法不再像ASP或ASP.NET Web Forms中使用的Request.Form
或Request.QueryString
等對象來獲取客戶端的數(shù)據(jù)。
產(chǎn)生操作結(jié)果
操作方法通常會返回一個ActionResult
類型對象产禾,但它的類型并不是一個數(shù)據(jù)容器排作。確切地說,它是一個抽象類亚情,提供通用編程界面妄痪,代表操作方法進一步的操作。
public abstract class ActionResult
{
protected ActionResult(){}
public abstract void ExecuteResult(ControllerContext context);
}
通過重寫ExecuteResult()
方法楞件,派生類會獲得訪問任何由操作方法的執(zhí)行所產(chǎn)生的數(shù)據(jù)的權(quán)限衫生,并觸發(fā)一些后續(xù)操作。一般來說土浸,這些后續(xù)操作與一些瀏覽器的響應(yīng)生成有關(guān)罪针。
預(yù)定義操作結(jié)果類型
Action
動作方法運行完畢后的回傳值,通常是ActionResult
類別或其衍生類別Derived Class
黄伊。事實上泪酱,ActionResult
是一個抽象類,下列均是繼承自ActionResult
。
-
ViewResult
用來回傳一個View
-
RedirectResult
用來將網(wǎng)頁重定向 -
Content
用來回傳文件內(nèi)容 -
FileResult
用來回傳二進制文檔等
執(zhí)行操作結(jié)果的機制
public JavaScriptResult GetScript()
{
return JavaScript(js);
}
// JavaScript是Controller類的一個輔助器方法墓阀,充當(dāng)JavaScriptResult對象工廠的角色
protected JavaScriptResult JavaScript(string js)
{
// JavaScriptResult類提供公共屬性Script愈腾,它包含會寫入輸出流的腳本代碼。
return new JavaScriptResult(){Script = script};
}
/**JavaScriptResult**/
public class JavaScriptResult:ActionResult
{
public String Script {get; set;}
public override void ExecuteResult(ControllerContext context)
{
if(context == null) throw new ArgumentNullException("context");
// Prepare the response
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = "application/x-javascript";
if(Script != null)
{
response.Write(Script);
}
}
}
控制器的動作結(jié)果
控制器動作結(jié)果ActionResult
是控制器動作返回的結(jié)果岂津,即控制器返回給瀏覽器請求的響應(yīng)內(nèi)容虱黄。
ASP.NET MVC框架支持6種標(biāo)準(zhǔn)類型的動作結(jié)果
EmptyResult
表示無結(jié)果
ViewResult
表示返回HTML及標(biāo)記
public ViewResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
JsonResult
表示返回JSON結(jié)果
public JsonResult TestJson()
{
var jsonResult = new JsonResult();
jsonResult.Data = new object[]
{
new {UserID = 10010,UserName = "IronMan"},
new {UserID = 10012,UserName = "AntMan"},
};
jsonResult.Data = new { UserID = 100, UserName = "SuperMane" };
jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsonResult;
}
ContentResult
表示返回文本結(jié)果
public ContentResult Content()
{
return Content("Hello World");
}
RedirectResult
表示重定向到新的URL
public RedirectResult Goto(string url)
{
return Redirect(url);
}
RedirectToRouteResult
表示重定向到新的控制器動作上
public RedirectToRouteResult Reload()
{
return RedirectToAction("Index");
}
控制器的視圖數(shù)據(jù)
View和Action之間前后臺數(shù)據(jù)傳遞的方式
- 弱類型
ViewData[""]
- 動態(tài)型
dynamic
的ViewBag
- 動態(tài)類型
Model
- 臨時存儲
TempData[""]
- 后臺
return View(data)
存入ViewData.Model
- 前臺
Model
即WebViewPage.Model
使用強類型視圖@model 類型
寫在View
最頂部,@ViewData.Model
簡寫為@Model
吮成、@Html.xxFor(x=>x.**)
橱乱。使用強類型的好處是提供智能提示,實現(xiàn)編譯時錯誤檢查粱甫,防止寫錯字段泳叠。
ViewBag.Message = "Your application description page.";
ViewData、TempData茶宵、ViewBag的區(qū)別
三者都是容器危纫,能存儲常量和變量,也能存儲集合乌庶。
-
ViewData
和ViewBag
ViewBag
和ViewData
屬性是同一份數(shù)據(jù)的不同表現(xiàn)形式种蝶,本質(zhì)上都是ViewDataDictionary
,二者之間數(shù)據(jù)共享瞒大。
ViewData
為對象型螃征,ViewBag
為Dynamic
動態(tài)對象,動態(tài)類型會在程序運行時動態(tài)解析透敌,可為其指定任意屬性盯滚,最終動態(tài)屬性名作為數(shù)據(jù)字典的鍵名。動態(tài)類型dynamic
和對象型object
的區(qū)別是在dynamic
使用時會自動根據(jù)數(shù)據(jù)類型轉(zhuǎn)換酗电,object
則需要我們自己去強制轉(zhuǎn)換魄藕。
ViewBag
只是在ViewData
上多了一層Dynamic
控制,可以說是訪問ViewData
的另一種方式撵术。理論上ViewBag
要比ViewData
慢一點兒背率。
-
ViewData
和TempData
ViewData
和TempData
屬性均返回一個具有字典鍵值對結(jié)構(gòu)的數(shù)據(jù)容器,TempData
存儲臨時數(shù)據(jù)荷荤,且設(shè)置的變量在被第一次讀取后會被移除退渗,也就是說TempData
設(shè)置的變量只能被讀取一次。ViewData
和ViewBag
只對當(dāng)前View
有用蕴纳,TempData
則可以在不同的Action
中進行傳值会油,類似Webform
中的Session
。TempData
的值在取了一次后會自動刪除古毛。TempData
用來在一次請求中同時執(zhí)行的多個Action
方法之間共享數(shù)據(jù)翻翩。
視圖
ASP.NET MVC 3引入Razor視圖引擎(Razor view engine)都许。Razor視圖模板使用.csshtml
文件擴展名,使用C#創(chuàng)建所要輸出的HTML嫂冻。
// 使用視圖模板生成HTML返回給瀏覽器
// 控制器方法(ActionMethod 操作方法)一般返回一個ActionResult或從ActionResult所繼承的類型
// 而非原始類型如字符串
public ActionResult Default()
{
return View();
}
# http://localhost:49184/Test/Welcome?message=hello&count=3
public ActionResult Welcome(string message, int count = 0)
{
ViewBag.Message = message;
ViewBag.Count= count;
return View();
}
# Welcome.cshtml
@{
ViewBag.Title = "Welcome";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Welcome</h2>
<ul>
@for (int i = 0; i < ViewBag.Count; i++)
{
<li>@ViewBag.Message</li>
}
</ul>
向瀏覽器輸出HTML源碼
# System.Web.IHtmlString
@Html.Raw("<i class="fa fa-th"></i>")
Razor布局的部分視圖
ASP.NET MVC中的部分視圖相當(dāng)于WebForm中的User Control胶征,由于頁面中會有許多重用的地方,可進行封裝重用桨仿。使用部分視圖的好處是既可以簡寫代碼睛低,又可以使頁面代碼更加清晰更好維護。
- Razor中的
@Html.Partial()
和@{Html.RenderPartial();}
Partial可直接輸出內(nèi)容服傍,在內(nèi)部將HTML轉(zhuǎn)換為MVCHtmlString
字符串钱雷,然后緩存起來,最后一次性輸出到頁面吹零。顯然罩抗,轉(zhuǎn)換過程會降低效率,通常使用RenderPartial代替灿椅。
- Razor中的
@{Html.RenderPartial();}
與@{Html.RenderAction();}
RenderPartial不需要創(chuàng)建Controller的Action套蒂,而RenderAction需要在Controller中創(chuàng)建加載的Action。RenderAction會先去調(diào)用Controller的Action再呈現(xiàn)視圖茫蛹,所以這里會在發(fā)起一個鏈接操刀。除了有HTML代碼外,還需通過讀取數(shù)據(jù)庫來渲染麻惶,就必須使用RenderAction馍刮,因此它可以在Action里調(diào)用Model里的方法讀取數(shù)據(jù)庫,渲染視圖后再呈現(xiàn)窃蹋,而RenderPartial沒有Action。
Razor中的
@{Html.RenderAction();}
和@Html.Action();
Action是直接輸出和Partial一樣存在一個轉(zhuǎn)換的過程静稻,但是不如RenderAction直接輸出到當(dāng)前HttpContext的效果高警没。Razor中的
@{Html.RenderPartial();}
和@RenderPage()
使用RenderPage來呈現(xiàn)部分,不能使用原來視圖的Model和ViewData振湾,只能通過參數(shù)來傳遞杀迹。而RenderPartial可使用原來視圖的Model和ViewData。
模型
使用.NET Framework數(shù)據(jù)訪問技術(shù)Entity Framework押搪,定義和使用模型類树酪。
Entity Framework, EF是支持代碼優(yōu)先(Code First)的開發(fā)模式,是相對于原始的CLR Object(POCO類)而言大州。
using System;
using System.Data.Entity;
namespace MovieManage.Models
{
//MovieDBContext類代表Entity Framework的電影數(shù)據(jù)庫類
//負(fù)責(zé)在數(shù)據(jù)庫中獲取续语、存儲、更新厦画、處理Movie類的實例
//MovieDBContext繼承自EF的DbContext基類
//為了能夠引入DbContext和DbSet疮茄,需要添加using System.Data.Entity;
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
//Movie表示數(shù)據(jù)庫中的電影滥朱,Movie對象的每個實例,將對應(yīng)數(shù)據(jù)庫表的一行力试,Movie類的每個屬性將對應(yīng)表的一列徙邻。
public class Movie
{
//屬性
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
}
MovieDBContext
類負(fù)責(zé)處理連接到數(shù)據(jù)庫,并將Movie
對象映射到數(shù)據(jù)表記錄的任務(wù)中畸裳。那么如何指定它將連接到數(shù)據(jù)庫呢缰犁?實際上,默認(rèn)EF
將預(yù)設(shè)使用LocalDB
怖糊。
SQL Server Express LocalDB民鼓,簡稱LocalDB是SQLServer Express輕量級版本的數(shù)據(jù)庫引擎。在用戶模式下啟動蓬抄、執(zhí)行丰嘉。LocalDB運行在一個特殊的SQL Server Express的執(zhí)行模式,所以運行使用MDF文件數(shù)據(jù)庫嚷缭。通常LocalDB的數(shù)據(jù)庫文件都保存在web項目的App_Data目錄下饮亏。
默認(rèn)的EF命名為對象上下文類的一個連接字符串,連接字符串connectionString
的名稱必須匹配DbContext
類的名稱阅爽。
# web.config
<connectionStrings>
<add name="MovieDBContext" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
CTRL+SHIFT+B
編譯并生成代碼后創(chuàng)建控制器
VS自動創(chuàng)建CRUD操作路幸、視圖被稱為scaffolding
。
System.Data.SqlClient.SqlException:“在與 SQL Server 建立連接時出現(xiàn)與網(wǎng)絡(luò)相關(guān)的或特定于實例的錯誤付翁。未找到或無法訪問服務(wù)器简肴。請驗證實例名稱是否正確并且 SQL Server 已配置為允許遠(yuǎn)程連接。 (provider: SQL Network Interfaces, error: 50 - 發(fā)生了 Local Database Runtime 錯誤百侧。無法創(chuàng)建自動實例砰识。有關(guān)錯誤詳細(xì)信息,請參閱 Windows 應(yīng)用程序事件日志佣渴。
)”
EF
EFEntity Framework
中會為每個管理的實體對象創(chuàng)建一個代理包裝類對象辫狼,其中會跟蹤實體對象的狀態(tài)和每個屬性的狀態(tài)。
EF對象管理器
每個通過EF數(shù)據(jù)上下文操作的實體對象辛润,都需要存在上下文的容器中膨处,一旦通過上下文的某個方法操作了實體對象后,上下文就會給它加上一個狀態(tài)標(biāo)識砂竖。
調(diào)用上下文的SaveChange()
方法時真椿,上下文context
會遍歷容器中的所有對象,并檢查它們的狀態(tài)標(biāo)識乎澄,并依照標(biāo)識的值進行相應(yīng)的SQL增刪改查操作突硝。
- 通常使用EF更新的方式,先查詢出要修改的數(shù)據(jù)三圆,然后再修改新值狞换。實體對象被修改的屬性在代理類對象里的對應(yīng)屬性狀態(tài)會被修改記錄下修改狀態(tài)避咆。等到調(diào)用
SaveChange()
方法時,EF會遍歷其管理的每個實體對象修噪,并根據(jù)其包裝類對象的狀態(tài)查库,生成增刪改查的SQL語句并執(zhí)行。
//實體上下文對象
EFEntities ctx= new EFEntities();
// 查詢出要修改的數(shù)據(jù)
User user= ctx.Users.Find(id);
//設(shè)置修改后的值
user.UpdatedAt = DateTime.Now;
//更新到數(shù)據(jù)庫
ctx.SaveChanges();
- 為了避免先查詢數(shù)據(jù)庫黄琼,可直接將被修改的實體對象添加到
EF
中管理樊销,此時為附加狀態(tài)Attached
,手動設(shè)置為未修改狀態(tài)Unchanged
脏款。若修改為Modified
那么將執(zhí)行更新全部列围苫,不過沒有賦新值的列,執(zhí)行生成的UPDATE SQL
語句時SET
的值仍舊是原來的值撤师。同時剂府,設(shè)置被修改的實體對象的包裝類對象對應(yīng)屬性為修改狀態(tài)。
User user = db.Users.Find(id);
if(user!=null){
// 將實體對象user添加到EF對象容器中剃盾,并獲取偽包裝類對象
DbEntityEntry<User> entry = db.Entry<User>(user);
// 將偽包裝類對象的狀態(tài)設(shè)置為Unchanged
entry.State = System.Data.EntityState.Unchanged;
// 對要修改的列Visited進行賦值
user.Visited = user.Visited + 1;
//設(shè)置被改變的屬性
entry.Property(a=>a.Visited).IsModified = true;
//提交到數(shù)據(jù)庫完成修改
int i = db.SaveChanges();//返回執(zhí)行修改的行數(shù)
if(i>0){
//...
}
}
// 執(zhí)行修改
[HttpPost]
public ActionResult Modify(BlogArticle model)
{
try
{
//將實體對象model加入EF對象容器中腺占,并獲取偽包裝類對象entry。
DbEntityEntry<BlogArticle> entry = db.Entry<BlogArticle>(model);
//將包裝類對象entry的狀態(tài)設(shè)置為unchanged
entry.State = System.Data.EntityState.Unchanged;
//設(shè)置被修改的屬性
entry.Property(a=>a.Title).IsModified = true;
entry.Property(a=>a.Author).IsModified = true;
entry.Property(a=>a.Category).IsModified = true;
//提交到數(shù)據(jù)庫以完成修改
db.SaveChanges();
//更新成功后重定向
return RedirectToAction("Index","Home");
}
catch(Exception e)
{
return Content("修改失敗..."+e.Message);
}
}
//執(zhí)行刪除
public ActionResult Delete(int id)
{
try
{
// 創(chuàng)建待刪除對象
BlogArticle ba = new BlogArticle();
ba.Id = id;
//將待刪除對象添加到EF對象管理容器
db.BlogArticles.Attach(ba);
//將對象包裝類的狀態(tài)標(biāo)識設(shè)置為刪除狀態(tài)
db.BlogArticles.Remove(ba);
//更新到數(shù)據(jù)庫
db.SaveChanges();
//跳轉(zhuǎn)重定向
return RedirectToAction("Index","Home");
}
catch(Exception e)
{
return RedirectToAction("友好提示頁面");
}
}
創(chuàng)建數(shù)據(jù)庫上下文
協(xié)調(diào)為給定的數(shù)據(jù)模型的實體框架功能的主類是數(shù)據(jù)庫上下文類痒谴。通過從派生來創(chuàng)建此類System.Data.Entity.DbContext
類衰伯。該類中可指定數(shù)據(jù)模型中包含哪些實體。
ashx
ashx
用于處理程序HttpHandler
积蔚,是.NET眾多Web組件的一種意鲸,.ashx
是其擴展名。一個httpHandler
接受并處理一個HTTP請求尽爆,類似于Java中的Servlet怎顾,Java中需繼承HttpServlet類。在.NET中需要實現(xiàn)IHttpHandler
接口教翩,此接口有一個IsReusable
成員杆勇,一個待實現(xiàn)的方法ProcessRequest(HttpContextctx)
。程序在ProcessRequest()
方法中接收到HTTP請求饱亿。成員IsReusable
指定此IHttpHanlder
實例是否可被用來處理多個請求。
.ashx
文件用于編寫web handler
闰靴,ashx
必須包含IsReuseable
屬性彪笼,代表是否可復(fù)用。如果要在.ashx
文件中使用SESSION
必須實現(xiàn)IRequiresSessionState
接口蚂且。
.ashx
程序適合產(chǎn)生供瀏覽器處理的配猫、無需回發(fā)處理的數(shù)據(jù)格式,例如用于生成動態(tài)圖片杏死、動態(tài)文本等內(nèi)容泵肄。