ASP.NET MVC4 将uiviewcontrollerr中的list传到view

&&&&&当前位置: &>&&>&&>&&&&ASP.NET MVC 学习3、Controller左手从Model获取数据,右手传递到View页面
ASP.NET MVC 学习3、Controller左手从Model获取数据,右手传递到View页面
作者:佚名&&来源:</&&发布日期:
本文内容:
1,学习了解Model的具体作用
2,新建Controller从Model中读取数据传递到View中
3,了解Entity Framework Code First
4,清楚View页面中@model 声明的强类型转换
5,查看View .cshtml的新的HTML书写方法
一,Add a new Model& ,了解Model的作用
Model:存放Model Class,对应数据库中的table,存取Table中的数据
Model Class中的每一个实例对应数据库Table中的一行,实例中的每一个属性对应Table中的每一列值(Model Class和DB Table的映射关系)
Entity FrameWork关系数据模型定义,
可以看右边这张图,回头有时间在看连接的介绍
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
Right-click Model floder&and Add a new Model Class:Movie.cs
using System.Collections.G
using System.L
using System.W
using System.Data.E
namespace MVCMovie.Models
//Moive 类就相当于数据库中的一张名为Movie的Table
//Movie 类实例化的对象相当于Table中的一行,实例的各个属性(ID,Title...)相当于Table中的列
public class Movie
public int ID { }
public string Title { }
public DateTime ReleaseDate { }
public string Genre { }
public decimal Price { }
//MovieDBContext class ,继承自Entity Framework中的DbContext,代表这Movie数据上下文
//MovieDBContext class ,读取、存储、更新Movie Class 实例
public class MovieDBContext : System.Data.Entity.DbContext
public DbSet&Movie& Movies { }
&配置WebConfig文件:
&connectionStrings&
&!--ModleDBContext连接字符串,使Movie数据存放于数据库中--&
&add name="MovieDBContext"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.Integrated Security=True"
providerName="System.Data.SqlClient" /&
&add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-MVCMovie-49;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-MVCMovie-49.mdf" providerName="System.Data.SqlClient" /&
&/connectionStrings&
&二,重建方案后,Add a new Control to Access Model&s Data ,了解数据Controller怎么从Model读取数据
Right-click Control floder and add a new control&&&
新添加的MovieController中就自动有了万增的增删查改的功能,CRUD (create, read, update, and delete),以及对应的CRUD View。页面中就可以creat,list,edit and delete Moive 实体(entries).&& ctrl+F5运行:&
2.1查看系统自动生成的 MoviesController 中的代码:
//实例化一个MovieDBContext db,然后用这个实例化的对象去增查改删(GRUD)
private MovieDBContext db = new MovieDBContext();
// GET: /Movies/
public ActionResult Index()
//返回 Movie Database 中的所有的 Movie实例
return View(db.Movies.ToList());
2.2 强类型模型,和@model关键字
我们之前有讲过ViewBage是一个动态对象,可以把数据或对象从Controller传递到View中。ASP.NET MVC同样提供了强类型(strongly typed data)到view template.这种强类型,VS可以在编译的时候更好的检查你的代码以及提供智能感知(richer IntelliSence).这种脚手架机制(scaffolding mechanism),在Controller的Methods中和View Template的Views中都有体现。
现在我们先来看看Controller中自动生成的code
// GET: /Movies/Details/
//以下方法,从实例化后的Movie对象中读取Movie数据
public ActionResult Details(int id = 0)
//如果id对应的Movie找到,则Return到Detail.cshtml中
Movie movie = db.Movies.Find(id);
if (movie == null)
return HttpNotFound();
return View(movie);
然后转到View&中的Details.cshtml看一下,第一行:
@model MVCMovie.Models.Movie
Detail.cshtml最上面的这一行的声明(Statement),指定了object是View可以接受的类型
之前从Model生成MovieController的时候同时 也生成了Controller中Method对应的View,@model的声明也是系统自动加上去的
@model指令,对Model对象强制类型转换,把Controller从Model中获取的数据传递到View Template中
例如,在Detail.cshtml中,code把movie 字段中的数据通过 stronged typed的 MVCMovie.Models.Movie 把数据从Controller传递到Detail.cshtml中
Index.cshtml中,仔细查看代码,看一下数据是怎样在View中显示出来的
@model IEnumerable&MVCMovie.Models.Movie&......& @foreach (var item in Model)&&& {&&&&&&& &tr&&&&&&&&&&&& &td&&&&&&&&&&&&&&&& @Html.DisplayFor(modelItem =& item.Title)&&&&&&&&&&& &/td&&&&&&&&&&&& &td&&&&&&&&&&&&&&&& @Html.DisplayFor(modelItem =& item.ReleaseDate)&&&&&&&&&&& &/td&&&&&&&&&&&& &td&&&&&&&&&&&&&&&& @Html.DisplayFor(modelItem =& item.Genre)&&&&&&&&&&& &/td&&&&&&&&&&&& &td&&&&&&&&&&&&&&&& @Html.DisplayFor(modelItem =& item.Price)&&&&&&&&&&& &/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&&&& }
这一行statement同样是vs automatically create的
@foreach中的每一个item就是一个Movie,这样的好处是代码可以在编译的时候进行检查并且进行智能填充你的Code,如下图:
三,Working with SQL Server LocalDB& 学习Code First
Entity Framework如果发现webconfig中的连接字符串所指向(pointed) Movies database不存在,Code First就会自动创建这个DB:
Double-click Movies.mdf ,我们可以看到Entity Framework为你创建的表:
Right-Click Movie table we see the data you Insert:
我们现在看到的这张Movie表就和之前的Model中的Movie是对应的,Code First就是在 Movie Class的基础上创建的这张表
Tips:在你关闭VS之前最好先 close Connection避免下次打开的时候弹出错误
现在你已经有了数据库,并且可以从简单的页面看到数据库中的list.
下一步我们会学习剩下的代码,并且创建一个查询页面
See You......
&&&#9742;&友情链接为什么我的ASP.NET MVC4程序View在输出的时候直接输出Model的成员名?
[问题点数:40分,结帖人u]
为什么我的ASP.NET MVC4程序View在输出的时候直接输出Model的成员名?
[问题点数:40分,结帖人u]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关推荐:
2014年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第四
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。Asp.Net MVC4系列--进阶篇之AJAX
本章将开始介绍MVC中Ajax的使用
以一个非Ajax版本开始
Controller
public class PeopleController : Controller
private readonly Person[] _personData = {
new Person {FirstName = "Iori",LastName = "Lan", Role = Role.Admin},
new Person {FirstName = "Edwin", LastName= "Sanderson", Role = Role.Admin},
new Person {FirstName = "John",LastName = "Griffyth", Role = Role.User},
new Person {FirstName = "Tik",LastName = "Smith", Role = Role.User},
new Person {FirstName = "Anne",LastName = "Jones", Role = Role.Guest}
public ActionResult Index()
return View("List");
public ActionResult GetPeople()
return View("List",_personData);
[HttpPost]
public ActionResult GetPeople(string selectedRole)
if (selectedRole == null || selectedRole == "All")
returnView("List",_personData);
var selected = (Role)Enum.Parse(typeof(Role), selectedRole);
return View("List",_personData.Where(p => p.Role ==selected));
public class Person
public string FirstName { }
public string LastName { }
public Role Role { }
public enum Role
@using MVCAjax.Models
@model IEnumerable
ViewBag.Title = "GetPeZ"/kf/ware/vc/" target="_blank" class="keylink">vcGxl";
Get People
FirstLastRole
@foreach (var p in Model) {
@p.FirstName
@p.LastName
@using (Html.BeginForm()) {
@Html.DropDownList("selectedRole",new SelectList(
new []{"All"}.Concat(Enum.GetNames(typeof(Role)))))
验证请求类型
在IE中打开F12->Network ,我们可以看到请求的发起者是click操作,因为不是xmlHttpRequest,因而不是ajax请求
使用Ajax重构代码
配置Unobstrusiveajax
打开web.config
确保这一行在appconfig节点中:
打开App_Start/BundleConfig.cs,确保已添加(默认已添加):
bundles.Add(newScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
"~/Scripts/jquery-ui-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*"));
原因:我们需要的是jquery.1.7.1.js 和jquery.unobstrucsive-ajax.min.js,这两个包已经包含了,在layout中render就可以了。
打开_layout.cs
在中render 这两个包:
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
注意:在View确保没有把@{layout=null},否则layout没有应用导致没有renderbundle,以致于无法render需要的script。
Controller 添加Action:
public ActionResult AjaxGetPeople()
return View("AjaxList");
public PartialViewResult GetPeoplePartial(string selectedRole = "All")
IEnumerable data = _personD
if(selectedRole != "All")
var selected = (Role)Enum.Parse(typeof(Role), selectedRole);
data =_personData.Where(p => p.Role == selected);
return PartialView("PeoplePartialList",data);
添加PartialViewPeoplePartialList.cshtml :
@using MVCAjax.Models
@model IEnumerable
@foreach (Person p in Model) {
@p.FirstName
@p.LastName
添加View: AjaxList.cshtml :
@using MVCAjax.Models
@model string
ViewBag.Title = "GetPeople";
var ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody"
Get People
FirstLastRole
@Html.Action("GetPeoplePartial", new {selectedRole= Model })
@using(Ajax.BeginForm("GetPeoplePartial",ajaxOpts)) {
@Html.DropDownList("selectedRole", new SelectList(
new []{"All"}.Concat(Enum.GetNames(typeof(Role)))))
F12->Network 查看请求
可以看到,initiator 为XMLHttpRequest ,验证了请求确实是Ajax。
分析Obstrusivejavascript 工作原理
这是MVC Framework生成的form tag,对于unobsrutive javascript 来说,他关心的是data-ajax=”true”和data-ajax开头的attribute,首先找到所有data-ajax=”true”的form,然后根据data-ajax-mode找到data-ajax-update的id(注意,unobstrusivejs 基于Jquery,需要加#)完成局部刷新。
Ajax Options
以下列出一些常用的AjaxOptions :
发起请求前弹出确认框,指定确认框的文字
HttpMethod
请求类型:POST,GET,PUT,DELETE等等
InsertionMode
Replace,Before,After, 默认为Replace
LoadingElementId
请求发出后,收到Server回应前弹出一个loading的div,这里指定div id
LoadingElementDuration
设置loading Div最多显示多少秒
UpdateTargetId
要局部更新的container id
发请求的url
Loading 和Confirmation
现在稍作改动,给例子加一个Confirmation和loading
准备loading的div和css
仅作为演示,我hard-code了loading div的位置,实际项目中需要调整
在AjaxOption中指定Id
var ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody" ,
Confirm = "Sure?",
LoadingElementDuration = 2000,
LoadingElementId = "loading"
在Controller中模拟一个长时间的任务
private void MockLongTimeProcessing()
Thread.Sleep(3000);
在partialview中调用一下
public PartialViewResult GetPeoplePartial(string selectedRole ="All")
MockLongTimeProcessing();
运行,查看效果:
Ajax链接的生成很简单。
稍作改动,看一下ajax链接的使用方法,在View(AjaxList.cshtml)中添加:
@foreach (string role in Enum.GetNames(typeof(Role))) {
@Ajax.ActionLink(role,"GetPeoplePartial",
new {selectedRole= role},
这样就可以了,其实就是调用Ajax.ActionLink函数,设置链接的文字,Action,以及参数,最后一个是AjaxOption,我们用的是前面一个demo的。
添加对Json的支持
改动Controller
和前面的步骤一样,添加两个Action,一个是服务第一次加载页面的 请求,我们返回View,一个是Ajax过来的,我们需要返回JsonResult:
public ActionResult
JsonList()
return View("JsonList");
public JsonResult GetPeopleJson(string selectedRole = "All")
IEnumerable data = _personD
if (selectedRole !="All")
var selected =(Role)Enum.Parse(typeof(Role), selectedRole);
data =_personData.Where(p => p.Role == selected);
return Json(data,JsonRequestBehavior.AllowGet);
添加View:
JsonList.cshtml
@using MVCAjax.Models
@model string
ViewBag.Title = "GetPeople";
var ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody",
&script type="text/javascript"&
function processData(data) {
var target =$("#tableBody");
target.empty();
for (var i = 0; i <data. i++) {
var person = data[i];
target.append("" + person.FirstName +""
+ person.LastName +"" + person.Role +"");
Get Json List
FirstLastRole
@Html.Action("GetPeoplePartial", new {selectedRole = Model })
@foreach (string role in Enum.GetNames(typeof(Role))) {
@Ajax.ActionLink(role, "GetPeople",
new {selectedRole = role},
new AjaxOptions {
Url = Url.Action("GetPeopleJson", new {selectedRole = role}),
OnSuccess = "processData"
为了简便演示,仅仅展示Json部分,笔者拿掉了Loading和Confirm的部分。
代码的核心在于OnSuccess = "processData" 。
当Ajax请求成功时,指向processData函数,在这个函数里面,我们拿到id(JqueryId)为#tableBody的表单,清空,手动拼html,并用jquery添加到这个html control中。这部分可以优化,可以选择handlebar.js,knockout.js 等js template。
在table body中调用了@Html.Action("GetPeoplePartial",new {selectedRole = Model }),和前面的原因一样,为了第一次加载时显示出所有人员列表。
另外,AjaxOptions中还有其他Callback类型;
: 发请求前
OnFailure :请求失败
OnSuccess :请求成功
OnComplete :请求完毕只需一步,快速开始
后使用快捷导航没有帐号?
查看: 2346|回复: 0
MVC多级Views目录ASP.NETMVC4路由重写及修改View的寻找视图的规则
主题帖子积分
MVC多级Views目录ASP.NET MVC4路由重写及修改View的寻找视图的规则" k! ^$ K1 _% z. x+ d' R6 H! i7 f3 ~
一般我们在MVC开发过程中,都会碰到这样的问题。页面总是写在Views文件夹下,而且还只能一个Controller的页面只能写在相应的以Controller名命名的文件夹下。如果我们写到别处呢?那么肯定会报错。这是MVC中的一个规定,必须这样写。
1、正常项目目录规则要求标准如下(图一)。我们要访问Index页面,只需要输入http://域名:端口号/Home/Index(本项目示例访问地址为http://localhost:64968/Home/Index)就可以访问了。我们之所以能够这样访问,是因为我们在项目创建之初系统就默认配置了一个默认的路由。我们可以按照这个默认的路由规则进行访问。默认的路由规则代码(路由目录:项目/App_Start/RouteConfig.cs)如下(代码一)。
图一& & public class RouteConfig0 _&&r- q/ T$ E# u
& && &&&public static void RegisterRoutes(RouteCollection routes)+ }5 p- z( ]- M3 r) P
& && && && &routes.IgnoreRoute(&{resource}.axd/{*pathInfo}&);
) C6 P- w: L. Z" F) z&&X
& && && && &routes.MapRoute(
& && && && && & name: &Default&,5 K% g& z7 R4 c& b
& && && && && & url: &{controller}/{action}/{id}&,
& && && && && & defaults: new { controller = &Home&, action = &Index&, id = UrlParameter.Optional }
& && && && &);) s, M- |5 n( P$ Q$ |& A0 v# [' M
& && &&&}: O2 D# L# G: }$ f5 }
& & }复制代码代码一- o6 J. L$ r3 }( A0 p+ U
2、那么我们要求的MVC多级目录规则如何呢?如下(图二)。如果我们要访问Admin下的DemoController里面的Index页面,那么我们输入http://域名:端口号/Demo/Index(本项目示例访问地址为http://localhost:64968/Demo/Index),通过这肯定是访问不了的(无法找到资源。)。因为DemoController根本就不在Controllers的根目录下,而是在Controllers/Admin下,这样我们根本就找不到DemoController。那么我们输入http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index)现在也是访问不了的(无法找到资源。),那么我们就需要添加一个路由配置了,因为以前的默认路由只能通过{Controller}/{Action}/{Id}这种方式访问,就是必须以Controller开头。我们重新配置的路由(路由目录:项目/App_Start/RouteConfig.cs)添加一条规则如下(代码二)。" A+ j5 S$ `9 Z
& & public class RouteConfig# a8 }5 l+ G' W+ {&&l' |" X
& && &&&public static void RegisterRoutes(RouteCollection routes)- S: J$ I6 y7 b0 Z( D
& && &&&{$ r' x" F7 g6 U# N
& && && && &routes.IgnoreRoute(&{resource}.axd/{*pathInfo}&);! I. E! ~. A&&V* i! k0 G$ ^3 s
- x# h# `&&h3 m! [% U&&C3 a
& && && && &//路由规则匹配是从上到下的,优先匹配的路由一定要写在最上面。路由匹配成功以后,不会继续匹配下去。- a' u&&m" Q&&x9 Y! ~# C+ {) \
& && && && &routes.MapRoute(
& && && && && & name: &Admin&,
& && && && && & url: &Admin/{controller}/{action}/{id}&,
& && && && && & defaults: new { controller = &Home&, action = &Index&, id = UrlParameter.Optional }- ]* ~4 ^! x# Y# I3 L6 e&&V+ N
& && && && &);
& && && && &routes.MapRoute(* J1 S, A4 i" ^# m0 D- t6 l. ^
& && && && && & name: &Default&,0 I, s& p' \1 B
& && && && && & url: &{controller}/{action}/{id}&,
& && && && && & defaults: new { controller = &Home&, action = &Index&, id = UrlParameter.Optional }
& && && && &);, w# j5 M* p+ {&&t. N. i. l5 J
& && &&&}7 C; J&&[5 R&&u- C" V% W( t
& & }复制代码代码二8 ^4 j( _' _2 X8 H& W9 }& v
3、那么现在我们再次输入http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index),能找到Views/Admin/Demo/Index.cshtml这个页面吗?显然是不能的(未找到视图。),因为除了路由配置怎么访问Controller外,寻找Views里面的页面也有自己的规则。测试结果肯定是找不到页面,我们看看错误信息(图三)就知道他是怎么寻找cshtml页面了。
图三& V; C: H) l&&^
据错误信息搜索位置只搜索这些地址,这里我只写Razor视图的地址,写成通配符就是:; l. g, q6 w# s5 o3 {$ M& U
Views/{1}/{0}.cshtmlViews/Shared/{0}.cshtml
{1}表示Controller的名称,{0}表示视图名称,Shared是存放模板页的文件夹。一看就很清楚了。这个就是寻找视图的规则,所以我们存放在Admin/Demo/Index.cshtml的存放规则就不满足。所以不能正常访问。按照此规则我们创建Views/Demo文件夹,并创建文件Views/Demo/Index.cshtml(图四)。至此http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index)则可以访问(图五),但是不是我们所要求的,既然我们Controller区分存放了,我们肯定也希望Views也能够这样存放的。6 a& C# H&&Z1 _' v
; ^&&I4 a& Q0 X. ]. o5 ^3 l1 K
4、Views存放规则如何修改呢?现在就开始修改寻找规则。第一先创建一个RouteViewEngine.cs类。类代码(代码三),规则重新定义好后将这个规则注册到系统中,将在Global.asax中注册一下,这样我们就可以通过自己的方式来访问了。0 Q; T8 ]0 Z3 K1 [# G( S&&_5 @
using System.Collections.G
using System.L' b5 C5 L. U- S
using System.W: q% @! t: y* ]
using System.Web.M
namespace MvcRouteDemo$ [; N: R& e+ D0 g
{- G5 d&&P, X& O1 O! X9 z+ m' U
& & public sealed class RouteViewEngine : RazorViewEngine4 z/ C* R& H, U" J2 q
& && &&&public RouteViewEngine()
& && &&&{* Q# E: m9 X$ M4 ]
& && && && &ViewLocationFormats = new[]/ `; M! |3 o&&S9 }
& && && && &{
& && && && && & &~/Views/{1}/{0}.cshtml&,9 E5 T4 r0 [: U7 g
& && && && && & &~/Views/Shared/{0}.cshtml&,
& && && && && & &~/Views/Admin/{1}/{0}.cshtml&//这是我们添加的规则" U+ r* |; _; M
& && && && &};( P8 s& e) t% Q; E
& && &&&}$ W&&K+ [' p/ h% d2 @3 [
& && &&&public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache). `7 y: H- `&&z
& && && && &return base.FindView(controllerContext, viewName, masterName, useCache);
& & }4 S$ |( x' U+ Y$ G; @
}复制代码代码三
5、Global.asax注册操作(代码四)。
& & public class MvcApplication : System.Web.HttpApplication
& & {. I& X# @4 m4 `6 R( p
& && &&&protected void Application_Start()
& && && && &AreaRegistration.RegisterAllAreas();! k: X&&x" h0 O! Y8 u' }6 w
. |3 |0 H0 _7 G5 q0 K) s) `& c: M% j& P
& && && && &WebApiConfig.Register(GlobalConfiguration.Configuration);
& && && && &FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);. H; {* D5 U) I/ f/ E
& && && && &RouteConfig.RegisterRoutes(RouteTable.Routes);( S& l, S0 a- A
& && && && &BundleConfig.RegisterBundles(BundleTable.Bundles);
# _) f2 T: o% s/ F8 \
& && && && &RegisterView();//注册视图访问规则到系统中2 N2 c9 Z7 t& M, b7 n( }3 Z0 E
& && &&&}( Q/ b, v: I' Z' L# ^0 J* V- W: v
8 K( Q7 D' d3 t1 _8 d&&e3 \* @
& && &&&protected void RegisterView()* F, y- e! y8 A4 h
& && &&&{" Q; s" P8 `. Z$ G% e
& && && && &ViewEngines.Engines.Clear();
& && && && &ViewEngines.Engines.Add(new RouteViewEngine());
& && &&&}7 O& v. Y. U1 O, i! d
& & }复制代码代码四# n* i/ t$ T; L
5、最后删除(图四)之前所修改路由表测试的文件夹删除,再次访问http://域名:端口号/Admin/Demo/Index(本项目示例访问地址为http://localhost:64968/Admin/Demo/Index)就可以实现我们的目的(图六)。
图六, E3 H7 J* l' V&&`, D! B3 P
最终送上本次示例项目。" j$ N7 e* @' j2 i/ Q" F
4 E# P# V. t5 ^6 T, h
2 ^( o. q) G0 o: T/ L7 {
本帖子中包含更多资源
才可以下载或查看,没有帐号?
积极宣传本站,为本站带来更多注册居民
Powered byAsp.Net MVC4 系列-- 进阶篇之路由(1) - 推酷
Asp.Net MVC4 系列-- 进阶篇之路由(1)
创建一个路由 &
打开 RouteConfig.cs &,发现已经创建了一个默认路由 :
routes.MapRoute(
name:&Default&,
url:&{controller}/{action}/{id}&
defaults: new { controller =&Home&, action = &Index&, id = UrlParameter.Optional }
为了说明路由的url匹配过程,暂时comment掉default参数。
打开Global.cs ,可以看到路由配置文件已经注册:
protected void Application_Start()
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
关于路由工作方式
Asp.net MVC Framework 的路由部分,是插入在http pipeline中的,当接受到http请求,会寻找注册的路由表(在ApplicationStart时候注册,就是应用启动时候),找到路由规则,获取每个路由规则的pattern,试图匹配当前请求合适的那个route,匹配成功,则解析出controller和action,从controllerfactory找到相应的controller,把请求传递给action,如果请求中传参,路由还会解析出参数,给action。
下面是几种url匹配的例子:
Controller =Admin,Action=Index
Controller=Index,Action=Admin
Controller=Apples,Action=Oranges
匹配失败,Segment太少
http://mysite/Admin/Index/Soccer
匹配失败,Segment太多
路由会调用route handler来完成路由过程,默认的,mvc应用会使用MVCRouteHandler.手动添加一个Route,就可以体现出来:
routes.Add(&MyRoute&,newRoute(&{controller}/{action}&, new MvcRouteHandler()));
指定默认(default)
刚才说明url匹配时候,拿掉了default参数,这时我们一起看看default参数的作用。
routes.MapRoute(
name:&Default&,
url:&{controller}/{action}/{id}&,
defaults: new { controller = &Home&, action =&Index&, id = UrlParameter.Optional }
可以看到最后一个参数,指定了一个默认的controller和action。
Controller = Home ,action=Index
</Customer
Controller=Customer ,action=Index
</Customer/List
Controller=Customer, action=List
</Customer/List/All
匹配失败,segment太多
定值Segment
场景1,所有请求中第一个Segment为”public”的,需要统一处理,因此定义一个路由:
routes.MapRoute(name: &PublicReqRoute&, url:&Public/{controller}/{action}&,
defaults: new {controller = &PublicHome&, action =&Index&});
匹配结果:controller = PublicHome,action=Index
场景2,请求中以public开始的,需要统一处理,定义路由:
routes.MapRoute(name: &PublicReqRoute&, url:&Public{controller}/{action}&,
defaults: new {controller = &PublicHome&, action =&Index&});
示例url: Http:/mysite/PublicX/
匹配结果:controller=X,action=Index
场景3:有个controller或action不工作,需要改个bug,把所有原来指向这个controller的请求暂时路由到首页:
routes.MapRoute(&myshop&,&Shop/OldAction&,
new { controller = &Home&, action =&Index& });
注意:路由是按着添加顺序依次解析的,因此把最特殊的那个路由放在前面,避免先fall 到相对generall的那个。
对于Route:
routes.MapRoute(
name:&Default&,
url:&{controller}/{action}/{id}&,
defaults: new { controller = &Home&, action =&Index&, id = UrlParameter.Optional }
Action 中使用RouteData.Values获取传入的id:
public ActionResult CustomVariable() {
ViewBag.Controller = &Home&;
ViewBag.Action = &CustomVariable&;
ViewBag.CustomVariable = RouteData.Values[&id&];
return View();
使用mvcframework Route System自动传参机制
除了使用RouteData.Values取出传入的参数,可以更简单的定义个参数在action,但是
参数名要和
定义的相同
ActionResult
CustomVariable(string id) {
ViewBag.Controller = &Home&;
ViewBag.Action = &CustomVariable&;
ViewBag.CustomVariable =
return View();
,id就会自动被赋值为15传入action
定义可选参数
依然对于url:
routes.MapRoute(
name:&Default&,
url:&{controller}/{action}/{id}&,
defaults: new { controller = &Home&, action =&Index&, id = UrlParameter.Optional }
Id=UrlParameter.Optional,此时id就是可选参数
Controller=home ,action=Index
</customer
Controller=customer, action=Index
</customer/List
Controller=customer, action=List
</customer/List/All
Controller=customer , action=List, Id=All
</customer/List/All/Delete
url 匹配失败
如果没有传参,action提供了id参数,那么id此时就为null;
ActionResultCustomVariable(string id) {
ViewBag.Controller = &Home&;
ViewBag.Action = &CustomVariable&;
ViewBag.CustomVariable = id == null ? &&novalue&& :
return View();
作为另一个选择,可以指定一个默认参数,如果没url没传值,默认参数值就会被使用。
ActionResultCustomVariable(string id = &DefaultId&) {
ViewBag.Controller = &Home&;
ViewBag.Action = &CustomVariable&;
ViewBag.CustomVariable =
return View();
使用{*catchall}捕捉超出数量的segment
例如,对于这条route:
routes.MapRoute(&MyRoute&,&{controller}/{action} /{*catchall}&,
new { controller = &Home&, action =&Index&,
id = UrlParameter.Optional });
由于使用了{*catchall},对于url:
此时,controller=Home,Action=Index, catchall=”All/More/More/More”
这样,就把解析剩下segment的工作交给了自己处理
解决在不同namespace的同名controller
例如现在有两个controller,在不同的命名空间:
namespace UrlsAndRoutes.Controllers {
public class HomeController : Controller {
public ActionResult Index() {
ViewBag.Controller = &Additional Controllers - Home&;
ViewBag.Action = &Index&;
return View(&ActionName&);
namespace UrlsAndRoutes.AdditionalControllers {
classHomeController : Controller {
ActionResultIndex() {
ViewBag.Controller = &Additional Controllers -Home&;
ViewBag.Action = &Index&;
return View(&ActionName&);
对于这种情况,可能希望路由先在一个指定的命名空间里找,找到了返回:
routes.MapRoute(&MyRoute&,&{controller}/{action}/{id}/{*catchall}&,
new { controller = &Home&, action =&Index&,
id = UrlParameter.Optional
new[] { &URLsAndRoutes.AdditionalControllers& });
关键在于最后的那个命名空间参数,mvc framework会优先找 “URLsAndRoutes.AdditionalControllers”里面的controller,如果没找到,会搜索其余的命名空间。
注意,这个new []{}数字里的参数是平行的,也就是说,如果mvc framework在这些命名空间里找到多个同名controller,不会找到第一个就返回,依然会抛出异常,例如:
new[] { &URLsAndRoutes.AdditionalControllers&,&UrlsAndRoutes.Controllers&});
mvc framework会在指定的命名空间数组里找,由于找到了多个homecontroller,因此抛出异常。
如果希望这样:指定多个命名空间,找到了第一个就返回,怎么做?
可以配置多条route:
routes.MapRoute(&AddContollerRoute&,&Home/{action}/{id}/{*catchall}&,
new { controller = &Home&, action =&Index&,
id = UrlParameter.Optional },
new[] { &URLsAndRoutes.AdditionalControllers& });
routes.MapRoute(&MyRoute&,&{controller}/{action}/{id}/{*catchall}&,
new { controller = &Home&, action =&Index&,
id = UrlParameter.Optional },
new[] { &URLsAndRoutes.Controllers& });
mvc framework就会按着添加的顺序依次查找匹配的controller和action,找到了把解析好的参数(如果有)传递给action就返回了。
只允许mvc framework在指定的 namespace里找,如何做?
Route myRoute=routes.MapRoute(&AddContollerRoute&,
&Home/{action}/{id}/{*catchall}&,
new { controller = &Home&, action =&Index&,
id = UrlParameter.Optional },
new[] { &URLsAndRoutes.AdditionalControllers& });
myRoute.DataTokens[&UseNamespaceFallback&] =
由于把DataTokens[“UseNamespaceFallback”] 设为false,因此mvcframework在指定的命名空间:URLsAndRoutes.AdditionalControllers&里面找完了,就不去其他地方找了。
给路由加限制
可以加正则限制在controller和action:
routes.MapRoute(&MyRoute&,&{controller}/{action}/{id}/{*catchall}&,
new { controller = &Home&, action =&Index&, id = UrlParameter.Optional },
new { controller = &^H.*&},
new[] { &URLsAndRoutes.Controllers&});
由于给controller加上了正则表达式:”^H.*”的限制,因此对于url匹配了urlpattern,解析出controller,如果不是以H开头的,也会被过滤掉。
类似的,也可以使用给action加正则限制:
new { controller = &^H.*&, action =&^Index$|^About$&}
这样,就限制了action必须是Index和About。
使用Http Method限制
可以限制请求是Get ,Post亦或是Put ,Delete等类型的。
new { controller = &^H.*&, action =&Index|About&,
httpMethod = new HttpMethodConstraint(&GET&) } ,
&这样,就限制了请求必须是Get方式的。
注意,给route加httpmethod限制,和给controller还有action加httpmethod区别在于,route在httppipeline很早的位置就被处理了,而到controller和action的时候,已经是httppipeline很晚的时候了,controller和action已经被解析了,参数也已经被解析了(如果有)。
自定义限制
Mvc 提供了IRouteConstranit 接口,可以自己定义限制,通过实现这个接口:
public class UserAgentConstraint : IRouteConstraint {
private string requiredUserA
public UserAgentConstraint(string
agentParam) {
requiredUserAgent = agentP
boolMatch(HttpContextBase
httpContext, Routeroute, string
parameterName,
RouteValueDictionary
values,RouteDirection routeDirection) {
return httpContext.Request.UserAgent != null &&
httpContext.Request.UserAgent.Contains(requiredUserAgent);
以上代码,实现了一个限制,必须Request对象中的代理对象不为空,也就是必须使用代理才能访问,并且代理名称包含指定的名称。
使用自定义限制:
routes.MapRoute(&ChromeRoute&,&{*catchall}&,
new { controller = &Home&, action =&Index& },
customConstraint = newUserAgentConstraint(&Chrome&)
new[] { &UrlsAndRoutes.AdditionalControllers& });
这样,就实现了,必须使用chrome才能访问的限制。
让访问物理文件目录的请求也参与路由
默认情况下,route system会先检查url是否指向了一个物理文件目录,如果是,返回找到这个文件,返回;否则,执行注册到路由表里面的每一条route。也就是说,指向物理文件目录的请求实际在mvc路由机制之前已经被处理掉了,默认没有参与路由。
如果要改变这个行为,例如访问
& ,不希望route去找resource/pic物理目录,而希望route找resourcecontroller ,pic action,那么:
在注册路由时,加上
routes.RouteExistingFiles =
这样,本地文件的检测 就会在路由机制执行之后了。
在路由前后,httppipeline的示意图
其中,httpmodule 1和 httpmodule2 在pipeline上面routesystem前后的两个module。
加上route.RouteExistingFiles=true
Route system中,就会先执行MVC Route,后执行CheckDisk Files .最后,为物理文件指定一个route:
routes.MapRoute(&DiskFile&,&Content/StaticContent.html&,
controller = &Resource&,
action = &List&,
By Passing Route System
有些访问资源文件的请求,是需要ignore的,这种需求直接用ignoreRoute就可以了:
routes.IgnoreRoute(&Content/{filename}.html&);
这样,对于url:
的请求就被route忽略了,访问页面,就会出现资源无法找到和404错误:
HTTP Error 404.0 - Not Found
The resource you are looking for has beenremoved, had its name changed, or is temporarily unavailable.
已发表评论数()
&&登&&&录&&
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见

我要回帖

更多关于 uiviewcontroller 的文章

 

随机推荐